bluetooth/btstack/l2cap/l2capCommand.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/l2capCommand.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,331 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implements the handling of l2cap signal packets (both inbound and outbound).
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <bluetooth/logger.h>
+#include "l2capCommand.h"
+
+#include "l2capSigPacketConnection.h"
+#include "l2capSigPacketConfigure.h"
+#include "l2capSigPacketDisconnection.h"
+#include "l2capSigPacketEcho.h"
+#include "l2capSigPacketCommandReject.h"
+#include "l2capSigPacketInformation.h"
+#include "l2capSignalHandler.h"
+
+#include "btsockettimer.h"
+
+#include "l2signalmgr.h"
+
+#include "L2CapDebugControlInterface.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
+#endif
+
+// Static function that decodes the RMBufChain into the correct command returns pointer to base class
+TInt HL2CapCommand::DecodeCommand(RMBufChain& aCommandString, HL2CapCommand*& aCommand)
+	{
+	LOG_STATIC_FUNC
+	aCommand = NULL;
+	TInt rerr = KErrNone;
+	RMBufChain remainingBuffer;
+	
+	if(aCommandString.Length() >= KL2CapCommandHeaderLength)
+		{
+		aCommandString.Align(KL2CapCommandHeaderLength);
+		TUint8 code = (aCommandString.First())->Get(KCodeOffset);
+		TUint16 len = LittleEndian::Get16((aCommandString.First())->Ptr()+KLengthOffset);
+
+		// Check the command has a valid length.
+		if(len + KL2CapCommandHeaderLength <= aCommandString.Length())
+			{
+			TRAP(rerr, aCommandString.SplitL(len + KL2CapCommandHeaderLength, remainingBuffer));
+			if(rerr == KErrNone)
+				{
+				TInt cmdErr = KErrNone; 
+				switch(code)
+					{
+					case ECommandReject:
+						(void)HCommandReject::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EConnectionRequest:
+						cmdErr = HConnectionRequest::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EConnectionResponse:
+						(void)HConnectionResponse::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EConfigureRequest:
+						cmdErr = HConfigureRequest::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EConfigureResponse:
+						(void)HConfigureResponse::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EDisconnectionRequest:
+						cmdErr = HDisconnectRequest::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EDisconnectionResponse: 
+						(void)HDisconnectResponse::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EEchoRequest:
+						cmdErr = HEchoRequest::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EEchoResponse:
+						(void)HEchoResponse::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EInformationRequest:
+						cmdErr = HInformationRequest::NewCommandIfValid(aCommandString, aCommand);
+						break;
+					case EInformationResponse:
+						(void)HInformationResponse::NewCommandIfValid(aCommandString, aCommand);
+						break;
+
+					default:
+						// This is not a recognised command.
+						LOG1(_L("DecodeCommand Unrecognised Command, code = %d"), code);
+						aCommand = new HInvalidCommand(aCommandString);
+						break;
+					};
+					
+				if(cmdErr == KErrCorrupt)
+					{
+					aCommand = new HInvalidCommand(aCommandString);
+					}
+
+				if(!aCommand)
+					{
+					aCommandString.Free();
+					}
+
+				aCommandString.Assign(remainingBuffer);
+				}
+			}
+		else
+			{
+			// Invalid command length.
+			rerr = KErrCorrupt;
+			}
+		}
+	else
+		{
+		rerr = KErrCompletion;
+		}
+	return rerr; 
+	}
+	
+	
+HL2CapCommand::~HL2CapCommand()
+	{
+	LOG_FUNC
+	CancelResponseTimer();
+	iLink.Deque();
+	iCommand.Free();
+
+	L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EL2CapCommand,
+	                             L2capDebugInfo::EDeleted));
+	}
+
+HL2CapCommand::HL2CapCommand(RMBufChain& aCommand, 
+                             TUint8 aRTXTimerDuration,
+	                         TUint16 aERTXTimerDuration)
+ : iResponseTimerRunning(EFalse),
+   iRetransmissionCounter(0),
+   iRTXTimerDuration(aRTXTimerDuration),
+   iERTXTimerDuration(aERTXTimerDuration)
+	{
+	LOG_FUNC
+	TInt length;
+	iCommand.Assign(aCommand);
+	length = iCommand.Length();
+
+	if (length > KMBufSmallSize)
+		{
+		length = KMBufSmallSize;	// alignment of longer packets, causes problems
+		}
+	iCommand.Align(length);
+
+
+	L2CAP_DEBUG(ObjectAllocation(L2capDebugInfo::EL2CapCommand,
+	                             L2capDebugInfo::EAllocated));
+	}
+
+TInt HL2CapCommand::GetCommand(CL2CAPMux& aMuxer, RMBufChain& aBuffer)
+	{
+	LOG_FUNC
+	// Set the ID if this is a request.  If the ID has already
+	// been initialised do not overwrite it.  This could be
+	// a retransmission.
+	if(IsRequest() && ID() == KUninitialisedID)
+		{
+		SetID(aMuxer.NextSigId());
+		}
+		
+	TRAPD(rerr, iCommand.CopyL(aBuffer));
+	return rerr;
+	}
+
+
+/*static*/ TInt HL2CapCommand::ResponseTimerExpired(TAny* aL2CapCommand)
+	{
+	LOG_STATIC_FUNC
+	HL2CapCommand* cmd = reinterpret_cast<HL2CapCommand*>(aL2CapCommand);
+	cmd->HandleResponseTimerExpiry();
+	return EFalse;
+	}
+
+void HL2CapCommand::HandleResponseTimerExpiry()
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(iResponseSignalHandler != 0, Panic(EL2CAPNoResponseSignalHandler));
+	// Deque the command from the response queue.
+	iLink.Deque();
+	iResponseTimerRunning = EFalse;
+	
+	if(iRetransmissionCounter >= KNumberOfRetransmissions)
+		{
+		iResponseSignalHandler->CommandResponseFailure(this);
+		}
+	else
+		{
+		iResponseSignalHandler->AddToOutgoingQueue(this);
+		iRetransmissionCounter++;
+		}	
+	}
+	
+void HL2CapCommand::StartRTXTimer(TRTXTimerType aType, CL2CapSignalHandler& aSignalHandler)
+	{
+	LOG_FUNC
+	// Check that it is valid to start a timer on this message.
+	__ASSERT_DEBUG(IsRequest(), Panic(EL2CAPAttemptToStartRTxTimerForResponseCommand));
+
+	// Cancel any existing timers.
+	CancelResponseTimer();		
+		
+	TCallBack cb(ResponseTimerExpired, this);
+	iResponseTimerEntry.Set(cb);
+
+	TUint16 timerDuration;
+	if(aType == ERTXTimer)
+		{
+		timerDuration = static_cast<TUint16>((iRetransmissionCounter + 1) * aSignalHandler.Mux().AdjustRTXTimerForSniffMode(iRTXTimerDuration));
+		}
+	else
+		{
+		timerDuration = iERTXTimerDuration;
+		iRetransmissionCounter = KNumberOfRetransmissions;
+		}
+
+	BTSocketTimer::Queue(timerDuration * KL2ProtocolSecondTimerMultiplier, iResponseTimerEntry);
+	iResponseTimerRunning = ETrue;
+	
+	iResponseSignalHandler = &aSignalHandler;
+	}
+	
+void HL2CapCommand::CancelResponseTimer()
+	{
+	LOG_FUNC
+	if(iResponseTimerRunning)
+		{
+		BTSocketTimer::Remove(iResponseTimerEntry);
+		}
+	}
+
+TBool HL2CapCommand::StatefulResponse()
+	{
+	LOG_FUNC
+	return (Code() == EConfigureResponse) || (Code() == EConnectionResponse) || (Code() == EDisconnectionResponse);
+	}
+
+HInvalidCommand::HInvalidCommand(RMBufChain& aCommand)
+ : HL2CapCommand(aCommand)
+	{
+	LOG_FUNC
+	}
+
+HInvalidCommand::~HInvalidCommand()
+	{
+	LOG_FUNC
+	}
+
+TBool HInvalidCommand::ProcessCommand(CL2CapSignalHandler& aSignalHandler)
+	{
+	LOG_FUNC
+	if(aSignalHandler.HandleInvalidCommand(this))
+		{
+		// The command has been handled.  Delete it.
+		delete this;
+		return ETrue;
+		}
+	else
+		{
+		return EFalse;
+		}
+	}
+	
+
+/*static*/ void HL2CapCommand::PutByte(TUint8 aByte, TInt aOffset, RMBufChain& aCommand)
+	{
+	LOG_STATIC_FUNC
+	__ASSERT_ALWAYS(aCommand.First() && (aCommand.First())->Length() > aOffset,
+		            Panic(EL2CapPDUInvalidLength));
+	aCommand.First()->Put(aByte, aOffset); 
+	}
+
+/*static*/ void HL2CapCommand::PutLittleEndian16(TUint16 aShort, TInt aOffset, RMBufChain& aCommand)
+	{
+	LOG_STATIC_FUNC
+	__ASSERT_ALWAYS(aCommand.First() && (aCommand.First())->Length() > aOffset+1,
+		            Panic(EL2CapPDUInvalidLength));
+	LittleEndian::Put16((aCommand.First())->Ptr()+aOffset, aShort);	
+	}
+	
+
+/*static*/ void HL2CapCommand::PutLittleEndian32(TUint32 aLong, TInt aOffset, RMBufChain& aCommand)
+	{
+	LOG_STATIC_FUNC
+	__ASSERT_ALWAYS(aCommand.First() && (aCommand.First())->Length() > aOffset+3,
+		            Panic(EL2CapPDUInvalidLength));
+	LittleEndian::Put32((aCommand.First())->Ptr()+aOffset, aLong);	
+	}
+
+/*static*/ TUint8 HL2CapCommand::GetByte(TInt aOffset, const RMBufChain& aCommand)
+	{
+	LOG_STATIC_FUNC
+	__ASSERT_ALWAYS(aCommand.First() && (aCommand.First())->Length() > aOffset,
+		            Panic(EL2CapPDUInvalidLength));
+	return aCommand.First()->Get(aOffset); 
+	}
+	
+/*static*/ TUint16 HL2CapCommand::GetLittleEndian16(TInt aOffset, const RMBufChain& aCommand)
+	{
+	LOG_STATIC_FUNC
+	__ASSERT_ALWAYS(aCommand.First() && (aCommand.First())->Length() > aOffset+1,
+		            Panic(EL2CapPDUInvalidLength));
+	return (LittleEndian::Get16((aCommand.First())->Ptr()+aOffset)); 
+	}
+	
+/*static*/ TUint32 HL2CapCommand::GetLittleEndian32(TInt aOffset, const RMBufChain& aCommand)
+	{
+	LOG_STATIC_FUNC
+	__ASSERT_ALWAYS(aCommand.First() && (aCommand.First())->Length() > aOffset+3,
+		            Panic(EL2CapPDUInvalidLength));
+	return(LittleEndian::Get32((aCommand.First())->Ptr()+aOffset)); 
+	}