diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/l2cap/l2capCommand.cpp --- /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 +#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(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((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)); + }