diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/avdtp/avdtpSignallingMessages.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/avdtp/avdtpSignallingMessages.cpp Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,1606 @@ +// Copyright (c) 2003-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 avdtp signalling messages +// +// + +/** + @file + @internalComponent +*/ + +#include +#include "avdtpSignallingMessages.h" +#include "avdtpSignallingChannel.h" +#include "avdtputil.h" +#include "avdtp.h" + +#ifdef __FLOG_ACTIVE +_LIT8(KLogComponent, LOG_COMPONENT_AVDTP); +#endif + +using namespace SymbianBluetoothAV; + +CAvdtpSignallingMessage::CAvdtpSignallingMessage() + { + LOG_FUNC + Data().Init(); + } + +CAvdtpInboundSignallingMessage::CAvdtpInboundSignallingMessage(CSignallingChannel& aSignallingChannel) +: iSignallingChannel(aSignallingChannel) + { + LOG_FUNC + } + +/*static*/ void CAvdtpOutboundSignallingMessage::PrependSignallingHeaderL( + RMBufChain& aDest, + const TAvdtpPacketType& aPacketType, + const TAvdtpTransactionLabel& aTransLabel, + const TAvdtpMessageType& aMessageType, + TAvdtpMessage aSigId, + TInt aNumberSignalPackets) + { + LOG_STATIC_FUNC + RMBuf& header = *RMBuf::AllocL(); + aDest.Prepend(&header); + + TUint8 firstByte = + ((aTransLabel<(aNumberSignalPackets),1); + header.Put(lastByte,2); + break; + } + case EEnd: + case EContinue: + header.SetLength(KAvdtpMinimumSignallingContinuePacketLength); + header.Put(firstByte,0); + break; + } + + } + + +/* +Return True if more fragments in packet +*/ +TBool CAvdtpOutboundSignallingMessage::GetNextOutboundFragmentL(RMBufChain& aDest, TInt aMaxSize) + { + LOG_FUNC + TAvdtpPacketType pktType; + + if (!iFragInfo.iFragmented) + { + // no fragmentation already done - might be single or need fragmenting + __ASSERT_DEBUG(Data().Length()<=(0xff*aMaxSize), Panic(EAvdtpBadlyFormattedOutboundSignallingMessage)); + + if ((Data().Length()+ + KAvdtpMinimumSignallingSinglePacketLength) < aMaxSize) + { + //no fragmentation required + PrependSignallingHeaderL(Data(),ESingle,TransactionLabel(),iMessageType,Signal()); + aDest.Assign(Data()); //transfer ownership of Data to aDest + Deque(); // remove this from the outbound queue + return EFalse; //no more frags - returned whole packet + } + else + { + // Start fragment(ing) + //we can get MTU-3 bytes in the first pkt, MTU-1 in the rest + //just pretend it's 2 bytes longer than it is and divide by + //MTU - 1 + iFragInfo.iTotalPackets = ((Data().Length()+2)/(aMaxSize-1)); + //and add one if it wasn't an exact fit + if ((Data().Length()+2)%(aMaxSize-1)) + { + iFragInfo.iTotalPackets++; + } + iFragInfo.iPacketNumber=0; + iFragInfo.iFragmented=ETrue; + + pktType = EStart; + } + } + else + { + // continue and end parts + pktType = (iFragInfo.iPacketNumber<(iFragInfo.iTotalPackets-1)) ? EContinue : EEnd; + } + + PrependSignallingHeaderL(Data(), pktType, TransactionLabel(), iMessageType, + Signal(), iFragInfo.iTotalPackets); + + // copy into "fragment" (whole packet if Single!) amount of message that will fit + // the message here doesn't have the header, but we do know we need to fragment + // (MTU-3) for Start, (MTU-1) for Continue,End + TInt size = 0; + + switch (pktType) + { + case EStart: + size = aMaxSize - KAvdtpMinimumSignallingStartPacketLength; + break; + case EContinue: + size = aMaxSize - KAvdtpMinimumSignallingContinuePacketLength; + break; + case EEnd: + size = aMaxSize - KAvdtpMinimumSignallingEndPacketLength; + break; + case ESingle: // drop through + default: + __ASSERT_DEBUG(0, Panic(EAvdtpBadlyFormattedOutboundSignallingMessage)); + } + + Data().CopyL(aDest,0,size); + // and trim off the copied data from Data() + // esock workaround - panic if trim > size of chain + Data().TrimStart(Min(size, Data().Length())); + + if (iFragInfo.iPacketNumber++==iFragInfo.iTotalPackets) + { + // all fragments done + Deque(); + return EFalse; // no more fragments from this packet + } + + return ETrue; + } + +/** +Check that packet header is ok for the packet build state we're in +@param aFragment the next incoming fragment to validate +@return KErrNone if ok, KErrCorrupt if not. KErrAbort if fragment is an Abort packet +*/ +TInt CAvdtpInboundSignallingMessage::CheckPacketType(RMBufChain& aFragment, TAvdtpPacketType& aPacketType, TAvdtpMessageType& aMessageType, TAvdtpTransactionLabel& aTransactionLabel) + { + LOG_FUNC + //NB could be an Abort packet interleaved in building up the previous packet + TInt ret = KErrCorrupt; + + if (aFragment.First()) + { + TAvdtpPacketType packetType = static_cast((aFragment.First()->Ptr()[0] & KAvdtpPacketTypeMask) >> KAvdtpPacketTypeOffset); + TAvdtpMessageType messageType = static_cast((aFragment.First()->Ptr()[0] & KAvdtpMessageTypeMask) >> KAvdtpMessageTypeOffset); + TAvdtpTransactionLabel transactionLabel = static_cast((aFragment.First()->Ptr()[0] & KAvdtpTransactionLabelMask) >> KAvdtpTransactionLabelOffset); + + aMessageType = messageType; + aTransactionLabel = transactionLabel; + aPacketType = packetType; + + /* check if an abort has come in + The abort will be a single packet type + The message type will be a command + The indication (second byte) will EAvdtpAbort + if an abort has come in then return KErrAbort and + the abort will be correctly processed. The packetbuildstate will + be reset to EAwaitingNew + */ + if ((ESingle == packetType) && (ECommand == messageType)) + { + /* note that when checking for the signal identifier HERE + we haven't yet removed the first byte from the message + */ + if (aFragment.First()->Size() > 1) + { + TAvdtpMessage id = static_cast(aFragment.First()->Ptr()[1] & KAvdtpSignalIdentifierMask); + if (EAvdtpAbort == id) + { + return (KErrAbort); + } + } + } + + switch (iPacketBuildState) + { + case EAwaitingNew: + // if waiting for a new packet then packet type must be single or start + if ((packetType==ESingle)||(packetType==EStart)) + { + ret=KErrNone; + } + break; + case EAwaitingContinue: + // if waiting for continue then type must be continue, and the transaction label + // of this fragment must match the packet we're building. Ditto for message type + if ((packetType==EContinue) && + (transactionLabel==iPacketBuildLabel) && + (messageType==iMessageType)) + { + ret=KErrNone; + } + break; + case EAwaitingEnd: + // if waiting for end then type must be end, and the transaction label + // of this fragment must match the packet we're building. Ditto for message type + if ((packetType==EEnd) && + (transactionLabel==iPacketBuildLabel) && + (messageType==iMessageType)) + { + ret=KErrNone; + } + break; + } + } + return ret; + } + +void CAvdtpSignallingMessage::SetType(TAvdtpMessageType aType,TAvdtpMessage aMessage) + { + LOG_FUNC + iSignal = aMessage; + iMessageType = aType; + } + + +CAvdtpOutboundSignallingMessage::~CAvdtpOutboundSignallingMessage() + { + LOG_FUNC + if (iMessageType==ECommand) + { + //OutBound Signalling message should never be EReserved + __ASSERT_DEBUG(Signal()!= EReserved,Panic(EAvdtpInvalidReservedValueInOutboundSignallingMessage)); + iCommandLabel.Close(); + } + Deque(); + } + +void CAvdtpOutboundSignallingMessage::AddSEPInfoL(const TAvdtpSEPInfo& aSEPInfo) + { + LOG_FUNC + // append SEP info to packet + TBuf8 SEPInfoBuf; + SEPInfoBuf.SetMax(); + + SEPInfoBuf[0] = aSEPInfo.SEID().PacketValue(); + if (aSEPInfo.InUse()) + { + SEPInfoBuf[0]|=(1<(Data().First()->Ptr()[0])) + : KErrCorrupt; + // pass up NULL SEP data + // NOTE: It is safe to set the third parameter below to NULL + // the ASSERT_DEBUG that might have been hit as a result won't be + // because 'err' cannot equal 'KErrNone'. + // SymbianBluetoothAV::ConvertToSymbianError::AvdtpError + // calls + // TInt SymbianBluetoothAV::ConvertToSymbianError::DoConvertError(TBluetoothAvDistributionError aAVError) + // which subtracts a TUint8 from -18045, and thus has to return a value + // between -18045 and -18045 - 255 = -18300 + iSignallingChannel.DiscoverConfirm(aLabel, err, NULL); + break; + } + case EGeneralReject: + { + TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.DiscoverConfirm(aLabel,err, NULL); + break; + } + } + } + +void CAvdtpInboundSignallingMessage::DoHandleGetCapsL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + TInt err = KErrNone; + + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpGetCapsCommandMinimumLength, KAvdtpGetCapsCommandMaximumLength); + iSignallingChannel.GetCapsIndication(aLabel,LocalSEIDL()); + break; + } + case EResponseAccept: + { + err = CheckPacketLength(KAvdtpGetCapsAcceptMinimumLength, KAvdtpGetCapsAcceptMaximumLength); + if (err==KErrNone) + { + // fish out the capabilities from mbufchain + // as this is immutable HBufC8 is chosen over RBuf8 + HBufC8* capsBuf = NULL; + capsBuf = HBufC8::NewMaxLC(Data().Length()); + TPtr8 des = capsBuf->Des(); + Data().CopyOut(des); + + // Remove unknown caps + CCapabilityRemoveUnknownVisitor* remover = new (ELeave) CCapabilityRemoveUnknownVisitor; + remover->Process(des); + delete remover; + + // parse caps for broken ones + CCapabilityValidateVisitor* validater = new (ELeave) CCapabilityValidateVisitor; + validater->Process(des); + + if (validater->Result()!=KErrNone) + { + CleanupStack::PopAndDestroy(capsBuf); + // drop (can't response to response) + // pass up zero as capabilities "seen" with the result code (in symbian range) + iSignallingChannel.GetCapsConfirm(aLabel, validater->Result(), 0); + } + else + { + // packet now only left with config payload + // pass ownership of buf + CleanupStack::Pop(capsBuf); + iSignallingChannel.GetCapsConfirm(aLabel, err, capsBuf); + } + + delete validater; + } + else + { + iSignallingChannel.GetCapsConfirm(aLabel, err); + } + break; + } + case EResponseReject: + { + err = CheckPacketLength(KAvdtpGetCapsRejectMinimumLength, KAvdtpGetCapsRejectMaximumLength); + err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(Data().First()->Ptr()[0])) : + KErrCorrupt; + // pass up zero as capabilities "seen" + iSignallingChannel.GetCapsConfirm(aLabel, err, 0); + break; + } + case EGeneralReject: + { + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.GetCapsConfirm(aLabel, err, 0); + break; + } + } + } + +/* +Handle a fully reassembled SetConfig command or response +*/ +void CAvdtpInboundSignallingMessage::DoHandleSetConfigL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + TInt err = KErrNone; + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpSetConfigCommandMinimumLength, KAvdtpSetConfigCommandMaximumLength); + + TSEID intSEID; + TSEID acpSEID; + acpSEID = LocalSEIDL(); + Data().TrimStart(1); // gulped ACP SEID + intSEID = RemoteSEIDL(); + Data().TrimStart(1); // gulped INT SEID + + if (!Data().Length()) + { + // empty configuration! not allowed? + AvdtpInternalUtils::PacketErrorLeaveL(EAvdtpBadPayloadFormat); + } + + RBuf8 caps; + CleanupClosePushL(caps); + caps.CreateMaxL(Data().Length()); + Data().CopyOut(caps); + + // parse caps for broken ones + CCapabilityValidateVisitor* validater = new (ELeave) CCapabilityValidateVisitor; + validater->Process(caps); + + CleanupStack::Pop(1); //caps + + if (validater->Result()!=KErrNone) + { + caps.Close(); + iSignallingChannel.SendSetConfigurationReject(aLabel, + AvdtpInternalUtils::SymbianErrorToAvdtpError(validater->Result()), + validater->InvalidCategory()); + } + else + { + // packet now only left with config payload, pass RBuf ownership + iSignallingChannel.SetConfigIndication(aLabel, acpSEID, intSEID, caps); + } + + delete validater; + break; + } + case EResponseAccept: + { + CheckPacketLength(KAvdtpSetConfigAcceptMinimumLength, KAvdtpSetConfigAcceptMaximumLength); + iSignallingChannel.SetConfigConfirm(aLabel, err, EServiceCategoryNull); + break; + } + case EResponseReject: + { + err = CheckPacketLength(KAvdtpSetConfigRejectMinimumLength, KAvdtpSetConfigRejectMaximumLength); + //Pull out the AVDTP error and convert to Symbian error + TAvdtpServiceCategory cat = EServiceCategoryNull; + if (err==KErrNone) + { + const TUint8* const rejData = Data().First()->Ptr(); + cat = static_cast(rejData[0]); + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(rejData[1])); + } + iSignallingChannel.SetConfigConfirm(aLabel, err, cat); + break; + } + case EGeneralReject: + { + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.SetConfigConfirm(aLabel, err, EServiceCategoryNull); + break; + } + } + } + +void CAvdtpInboundSignallingMessage::DoHandleGetConfigL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + TInt err=KErrNone; + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpGetConfigCommandMinimumLength, KAvdtpGetConfigCommandMaximumLength); + iSignallingChannel.GetConfigIndication(aLabel, LocalSEIDL()); + break; + } + case EResponseAccept: + { + err = CheckPacketLength(KAvdtpGetConfigAcceptMinimumLength, KAvdtpGetConfigAcceptMaximumLength); + iSignallingChannel.GetConfigConfirm(aLabel, err); + break; + } + case EResponseReject: + { + err = CheckPacketLength(KAvdtpGetConfigRejectMinimumLength, KAvdtpGetConfigRejectMaximumLength); + err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(Data().First()->Ptr()[0])) : + KErrCorrupt; + iSignallingChannel.GetConfigConfirm(aLabel,err); + break; + } + case EGeneralReject: + { + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.GetConfigConfirm(aLabel,err); + break; + } + default: + break; + } + } + +void CAvdtpInboundSignallingMessage::DoHandleReconfigL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpReConfigCommandMinimumLength, KAvdtpReConfigCommandMaximumLength); + + TSEID intSEID; + TSEID acpSEID; + acpSEID = LocalSEIDL(); + Data().TrimStart(1); // gulped ACP SEID + + if (!Data().Length()) + { + // empty configuration! not allowed? + AvdtpInternalUtils::PacketErrorLeaveL(EAvdtpBadPayloadFormat); + } + + RBuf8 caps; + CleanupClosePushL(caps); + caps.CreateMaxL(Data().Length()); + Data().CopyOut(caps); + + // parse caps for broken ones + CCapabilityValidateVisitor* validater = new (ELeave) CCapabilityValidateVisitor; + validater->Process(caps); + + CleanupStack::Pop(1); //caps + + if (validater->Result()!=KErrNone) + { + caps.Close(); + iSignallingChannel.SendReconfigureReject(aLabel, + AvdtpInternalUtils::SymbianErrorToAvdtpError(validater->Result()), + validater->InvalidCategory()); + } + else + { + // packet now only left with config payload + iSignallingChannel.ReconfigIndication(aLabel, acpSEID, caps); + } + + delete validater; + break; + } + case EResponseAccept: + { + CheckPacketLength(KAvdtpReConfigAcceptMinimumLength, KAvdtpReConfigAcceptMaximumLength); + iSignallingChannel.ReconfigConfirm(aLabel, KErrNone, EServiceCategoryNull); + break; + } + case EResponseReject: + { + TInt err = CheckPacketLength(KAvdtpReConfigRejectMinimumLength, KAvdtpReConfigRejectMaximumLength); + TAvdtpServiceCategory cat = EServiceCategoryNull; + if (err==KErrNone) + { + //Pull out the AVDTP error and convert to Symbian error + const TUint8* const rejData = Data().First()->Ptr(); + cat = static_cast(rejData[0]); + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(rejData[1])); + } + iSignallingChannel.ReconfigConfirm(aLabel, err, cat); + break; + } + case EGeneralReject: + { + TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.ReconfigConfirm(aLabel, err, EServiceCategoryNull); + break; + } + } + } + +void CAvdtpInboundSignallingMessage::DoHandleOpenL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpOpenCommandMinimumLength, KAvdtpOpenCommandMaximumLength); + iSignallingChannel.OpenIndication(aLabel, LocalSEIDL()); + break; + } + case EResponseAccept: + { + TInt err = CheckPacketLength(KAvdtpOpenAcceptMinimumLength, KAvdtpOpenAcceptMaximumLength); + iSignallingChannel.OpenConfirm(aLabel, err); + break; + } + case EResponseReject: + { + TInt err = CheckPacketLength(KAvdtpOpenRejectMinimumLength, KAvdtpOpenRejectMaximumLength); + err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(Data().First()->Ptr()[0])) : + KErrCorrupt; + iSignallingChannel.OpenConfirm(aLabel, err); + break; + } + case EGeneralReject: + { + TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.OpenConfirm(aLabel, err); + break; + } + default: + break; + } + } + +void CAvdtpInboundSignallingMessage::DoHandleStartL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + TInt err=KErrNone; + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpStartCommandMinimumLength, KAvdtpStartCommandMaximumLength); + // get list of seids + // copy out - the data at this point is just the SEID list + TInt numSEIDs = Data().Length(); + if (!numSEIDs) + { + AvdtpInternalUtils::PacketErrorLeaveL(EAvdtpBadPayloadFormat); + } + else + { + // we issue the starts individually + // as we cannot assume that the SEPs are within the same client process + // so even if we could send multiple SEIDs to each client process there is + // no synchronisation provided. + for (TInt i=0; i(Data().First()->Ptr()[1])) : + KErrCorrupt; + // ignore the SEID - the channel will have stored the SEID (and the Accept doesnt have it!) + iSignallingChannel.StartConfirm(aLabel, err); + break; + } + case EGeneralReject: + { + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.StartConfirm(aLabel, err); + break; + } + default: + break; + } //end switch + } + +void CAvdtpInboundSignallingMessage::DoHandleReleaseL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpCloseCommandMinimumLength, KAvdtpCloseCommandMaximumLength); + iSignallingChannel.ReleaseIndication(aLabel, LocalSEIDL()); + break; + } + case EResponseAccept: + { + TInt err = CheckPacketLength(KAvdtpCloseAcceptMinimumLength, KAvdtpCloseAcceptMaximumLength); + iSignallingChannel.ReleaseConfirm(aLabel, err); + break; + } + case EResponseReject: + { + TInt err = CheckPacketLength(KAvdtpCloseRejectMinimumLength, KAvdtpCloseRejectMaximumLength); + err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(Data().First()->Ptr()[0])) : + KErrCorrupt; + iSignallingChannel.ReleaseConfirm(aLabel, err); + break; + } + case EGeneralReject: + { + TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.ReleaseConfirm(aLabel, err); + break; + } + } + } + +void CAvdtpInboundSignallingMessage::DoHandleSuspendL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + TInt err = KErrNone; + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpSuspendCommandMinimumLength, KAvdtpSuspendCommandMaximumLength); + // get list of seids + // copy out - the data at this point is just the SEID list + TInt numSEIDs = Data().Length(); + if (!numSEIDs) + { + AvdtpInternalUtils::PacketErrorLeaveL(EAvdtpBadPayloadFormat); + } + else + { + // we issue the suspends individually + // as we cannot assume that the SEPs are within the same client process + // so even if we could send multiple SEIDs to each client process there is + // no synchronisation provided. + for (TInt i=0; i(Data().First()->Ptr()[1])) : + KErrCorrupt; + // ignore the SEID as the Signalling Channel will have stored it + iSignallingChannel.SuspendConfirm(aLabel,err); + break; + } + case EGeneralReject: + { + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.SuspendConfirm(aLabel,err); + break; + } + default: + break; + } + } + +void CAvdtpInboundSignallingMessage::DoHandleAbortL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + switch (iMessageType) + { + case ECommand: + { + TInt err = KErrNone; + + err = CheckPacketLength(KAvdtpAbortCommandMinimumLength, KAvdtpAbortCommandMaximumLength); + if (err==KErrNone) + { + iSignallingChannel.AbortIndication(aLabel, LocalSEIDL()); + } + break; + } + case EResponseAccept: + { + iSignallingChannel.AbortConfirm(aLabel); + break; + } + case EResponseReject: + case EGeneralReject: //General reject will be handled similar to Response Reject + { + //Don't expect this - spec a bit vague + // just throw away + break; + } + } + } + +void CAvdtpInboundSignallingMessage::DoHandleSecurityControlL(TAvdtpTransactionLabel aLabel) + { + LOG_FUNC + TInt err; + switch (iMessageType) + { + case ECommand: + { + CheckPacketLengthL(KAvdtpSecurityControlCommandMinimumLength, KAvdtpSecurityControlCommandMaximumLength); + // fish out the capabilities from mbufchain + // as this is immutable HBufC8 is chosen over RBuf8 + TSEID localSEID; + localSEID = LocalSEIDL(); + Data().TrimStart(1); // gulp SEID + HBufC8* securityData = HBufC8::NewMaxL(Data().Length()); + TPtr8 des = securityData->Des(); + Data().CopyOut(des); + //HBuf ownserhsip is transferred + iSignallingChannel.SecurityControlIndication(aLabel, localSEID, securityData); + + break; + } + case EResponseAccept: + { + err = CheckPacketLength(KAvdtpSecurityControlAcceptMinimumLength, KAvdtpSecurityControlAcceptMaximumLength); + // fish out the capabilities from mbufchain + HBufC8* securityData = HBufC8::NewMaxL(Data().Length()); + TPtr8 des = securityData->Des(); + Data().CopyOut(des); + + iSignallingChannel.SecurityControlConfirm(aLabel, err, *securityData); + + delete securityData; + break; + } + case EResponseReject: + { + err = CheckPacketLength(KAvdtpSecurityControlRejectMinimumLength, KAvdtpSecurityControlRejectMaximumLength); + err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(Data().First()->Ptr()[0])) : + KErrCorrupt; + iSignallingChannel.SecurityControlConfirm(aLabel, err, KNullDesC8); + break; + } + case EGeneralReject: + { + err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast(EAvdtpNotSupportedCommand)); + iSignallingChannel.SecurityControlConfirm(aLabel, err, KNullDesC8); + break; + } + } + } + + +/** +Splits the AVDTP message part from the packet +Returns a new mbufchain containing the message +The client has to free the input and output chains when convenient +*/ +/*static*/ RMBufChain CAvdtpInboundSignallingMessage::MessageL(RMBufChain& aPacket, const TAvdtpPacketType aPacketType) + { + LOG_STATIC_FUNC + TInt offset = 0; + + switch (aPacketType) + { + case ESingle: + case EEnd: + case EContinue: + __ASSERT_DEBUG(aPacket.Length() > 0, Panic(EAvdtpGotBadDataFromL2CAP)); + //if not in DEBUG mode, prevent MBuf panic by leaving here if + //we have received a corrupt frame. + User::LeaveIfError(aPacket.Length() > 0 ? KErrNone : KErrUnderflow); + offset = 1; + break; + case EStart: + __ASSERT_DEBUG(aPacket.Length() > 1, Panic(EAvdtpGotBadDataFromL2CAP)); + //if not in DEBUG mode, prevent MBuf panic by leaving here if + //we have received a corrupt frame. + User::LeaveIfError(aPacket.Length() > 1 ? KErrNone : KErrUnderflow); + offset = 2; + break; + } + RMBufChain message; + aPacket.SplitL(offset, message); + return message; + } + +/** +Assumes NOSP is at offset 1 +*/ +/*static*/ TUint8 CAvdtpInboundSignallingMessage::NumberSignalPackets(const RMBufChain& aChain) + { + LOG_STATIC_FUNC + return aChain.First()->Ptr()[1]; // The length was checked in MessageL, so we don't need to check it here. + } + +/** +Note for Start packets this assumes NOSP has been consumed, it takes the zeroth byte as the signal +Can only be used for Single and Start packets - no signal in Continue and End packets +*/ +/*static*/ TAvdtpMessage CAvdtpInboundSignallingMessage::SignalIdentifier(const RMBufChain& aChain) + { + LOG_STATIC_FUNC + TAvdtpMessage message; + if (aChain.First() == NULL) + { + message = EAvdtpNull; + } + else + { + message = static_cast(aChain.First()->Ptr()[0] & KAvdtpSignalIdentifierMask); + } + return message; + } + +/** +returns the (semantically local) SEID from the packet - leaves if bad seid +many commands received have SEID in the same place - this *assumes* that this is true +**/ +TSEID CAvdtpInboundSignallingMessage::LocalSEIDL() + { + LOG_FUNC + return TSEID::FromPacketL(Data().First()->Ptr()[0], ETrue); // The length of the packet is always checked by CheckPacketLengthL before this function is called + } + +/** +returns the (semantically remote) SEID from the packet - leaves if bad seid +many commands received have SEID in the same place - this *assumes* that this is true +**/ +TSEID CAvdtpInboundSignallingMessage::RemoteSEIDL() + { + LOG_FUNC + return TSEID::FromPacketL(Data().First()->Ptr()[0], EFalse); // The length of the packet is always checked by CheckPacketLengthL before this function is called + } + +/** +Returns what to do after packet sent: +e.g. setRTX, don't set RTX, or immediately scrub knowledge of sending +Whether or not the AVDTP Signalling RTX applies to this message +[calculated from the Message type based on GAVDTP 4.1.8] + +@return the action to use after sending +*/ +TPostSendAction CAvdtpOutboundSignallingMessage::PostSendAction() const + { + LOG_FUNC + if (iMessageType == ECommand) + { + //OutBound Signalling message should never be EReserved + __ASSERT_DEBUG(Signal()!=EReserved,Panic(EAvdtpInvalidReservedValueInOutboundSignallingMessage)); + switch(Signal()) + { + case EAvdtpGetCapabilities: + case EAvdtpDiscover: + case EAvdtpSecurityControl: + return EKeepDontSetRTX; + default: + return EKeepSetRTX; + } + } + else + { + return EDiscard; + } + } + + +/** +Used for inbound command checking where the leave is trapped and a response sent +*/ +void CAvdtpInboundSignallingMessage::CheckPacketLengthL(TUint aMin, TUint aMax) + { + LOG_FUNC + User::LeaveIfError(CheckPacketLength(aMin, aMax)); + } + +/** +Used for inbound responses - doesn't leave as we don't send a response, but we do tell the client +that their command has completed with an AVDTP error +*/ +TInt CAvdtpInboundSignallingMessage::CheckPacketLength(TUint aMin, TUint aMax) + { + LOG_FUNC + TInt ret = KErrNone; + + TInt pktLen = Data().Length(); + + if (pktLen>aMax || pktLenKMaxAvdtpNumSEPs) + { + return KErrCorrupt; + } + + if (aClientBuffer.MaxLength()<(numSEPs*sizeof(TAvdtpSEPInfo))) + { + return KErrNoMemory; + } + + // ok - parse + TInt err = KErrNone; + + for (TInt i=0;i<=numSEPs-1;i++) + { + TBuf8 dataBuf; + dataBuf.SetLength(KAvdtpPacketSEPInfoSize); + aMessageData.CopyOut(dataBuf,(i*KAvdtpPacketSEPInfoSize)); + + TAvdtpSEPInfo sepInfo; + sepInfo.SetSEID(TSEID::FromPacketL(dataBuf[0], EFalse)); + sepInfo.SetInUse(dataBuf[0] & 0x02 ? ETrue : EFalse); + sepInfo.SetMediaType(static_cast + (dataBuf[1]>>4)); + sepInfo.SetIsSink((dataBuf[1] & 0x08) ? ETrue : EFalse); + + err = aSEPCache.AddSEP(aAddr, sepInfo); + + if (err==KErrNone) + { + TPckg desc(sepInfo); + aClientBuffer.Append(desc); + } + } + + return err; + } + + +/*static*/ void AvdtpSignallingMessageSetConfiguration::Command::FormatL(CAvdtpOutboundSignallingMessage& aSignallingMessage, + TSEID aACPSEID, + TSEID aINTSEID, + const RBuf8& aConfiguration) + { + LOG_STATIC_FUNC + aSignallingMessage.AppendDataL(aACPSEID.PacketValue()); + aSignallingMessage.AppendDataL(aINTSEID.PacketValue()); + aSignallingMessage.AppendDataL(aConfiguration); + } + +/*static*/ void AvdtpSignallingMessageReconfigure::Command::FormatL(CAvdtpOutboundSignallingMessage& aSignallingMessage, + TSEID aACPSEID, + const RBuf8& aConfiguration) + { + LOG_STATIC_FUNC + aSignallingMessage.AppendDataL(aACPSEID.PacketValue()); + aSignallingMessage.AppendDataL(aConfiguration); + } + + +/*static*/ +void AvdtpSignallingMessage::Reject::FormatL(CAvdtpOutboundSignallingMessage& aSignallingMessage, + TBluetoothAvDistributionError aRejectionCode, const TDesC8* aRejectionData/*=NULL*/) + { + LOG_STATIC_FUNC + if (aRejectionData) + { + aSignallingMessage.AppendDataL(*aRejectionData); + } + aSignallingMessage.AppendDataL(aRejectionCode); + } + + +#ifdef _DEBUG +TBool CCapabilityFlogVisitor::Capability(TAvdtpServiceCategory /*aCat*/) + { +// FPrint(_L("Avdtp: Capability %d, payload %S"), aCat, &aCapPayload); + return ETrue; + } +#endif + + + +TPtrC8 CCapabilityExtractorVisitor::GetCapability() const + { + return iPtr; + } + + + +CCapabilityExtractorVisitor::CCapabilityExtractorVisitor(TAvdtpServiceCategory aRequiredCapability) +: iRequiredCapability(aRequiredCapability) + { + } + +TBool CCapabilityExtractorVisitor::Capability(TAvdtpServiceCategory aCat) + { + LOG_FUNC + if (aCat == iRequiredCapability) + { + iPtr.Set(CapabilityPayload()); + return EFalse; + } + else + { + return ETrue; + } + } + + +TBool CCapabilityValidateVisitor::Capability(TAvdtpServiceCategory aCat) + { + LOG_FUNC + // check lengths of payload of capability for known categories + // unknown categories are marked invalid + TBool valid = ETrue; + + switch (aCat) + { + case EServiceCategoryMediaTransport: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityMediaTransportMinimumLOSC, KAvdtpCapabilityMediaTransportMaximumLOSC); + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadMediaTransportFormat); + break; + case EServiceCategoryReporting: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityReportingMinimumLOSC, KAvdtpCapabilityReportingMaximumLOSC); + // spec doesn't (yet?) have a specific error code for this! use bad-payload instead + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadPayloadFormat); + break; + case EServiceCategoryRecovery: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityRecoveryMinimumLOSC, KAvdtpCapabilityRecoveryMaximumLOSC); + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadRecoveryFormat); + break; + case EServiceCategoryContentProtection: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityContentProtectionMinimumLOSC, KAvdtpCapabilityContentProtectionMaximumLOSC); + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadCpFormat); + break; + case EServiceCategoryHeaderCompression: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityHeaderCompressionMinimumLOSC, KAvdtpCapabilityHeaderCompressionMaximumLOSC); + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadRohcFormat); + break; + case EServiceCategoryMultiplexing: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityMultiplexingMinimumLOSC, KAvdtpCapabilityMultiplexingMaximumLOSC); + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadMultiplexingFormat); + break; + case EServiceCategoryMediaCodec: + valid = IsLOSCValid(CapabilityPayload().Length(), KAvdtpCapabilityMediaCodecMinimumLOSC, KAvdtpCapabilityMediaCodecMaximumLOSC); + // daft spec doesn't have one for this! use bad-payload instead + iResult = valid ? KErrNone : SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadPayloadFormat); + break; + + default: + // unknown capability + iResult = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadServCategory); + valid = EFalse; + } + + if (!valid) + { + // store the invalid details + iInvalidCategory = aCat; + } + + return valid; // at present this visitor causes termination at first bad category + } + +inline TInt CCapabilityValidateVisitor::Result() const + { + LOG_FUNC + return iResult; + } + +inline TAvdtpServiceCategory CCapabilityValidateVisitor::InvalidCategory() const + { + LOG_FUNC + return iInvalidCategory; + } + +TBool CCapabilityRemoveUnknownVisitor::Capability(TAvdtpServiceCategory aCat) + { + LOG_FUNC + + switch (aCat) + { + case EServiceCategoryMediaTransport: + case EServiceCategoryReporting: + case EServiceCategoryRecovery: + case EServiceCategoryContentProtection: + case EServiceCategoryHeaderCompression: + case EServiceCategoryMultiplexing: + case EServiceCategoryMediaCodec: + // Do nothing + break; + + default: + // unknown capability + CapabilityDes().Zero(); + } + + return ETrue; + } + +inline TBool CCapabilityValidateVisitor::IsLOSCValid(TUint aLOSC, TUint aMin, TUint aMax) + { + LOG_FUNC + return (aLOSC<=aMax && aLOSC>=aMin); + } + +// static forward functions to make more efficient than pointer-to-member-function +void CAvdtpInboundSignallingMessage::HandleDiscoverL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleDiscoverL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleGetCapsL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleGetCapsL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleSetConfigL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleSetConfigL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleGetConfigL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleGetConfigL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleReconfigL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleReconfigL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleOpenL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleOpenL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleStartL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleStartL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleReleaseL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleReleaseL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleSuspendL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleSuspendL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleAbortL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleAbortL(aLabel); + } + +void CAvdtpInboundSignallingMessage::HandleSecurityControlL(CAvdtpInboundSignallingMessage& aThat, TAvdtpTransactionLabel aLabel) + { + LOG_STATIC_FUNC + aThat.DoHandleSecurityControlL(aLabel); + } +