--- /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));
+ }