--- /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 <bluetooth/logger.h>
+#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<<KAvdtpTransactionLabelOffset) & KAvdtpTransactionLabelMask) |
+ ((aPacketType<<KAvdtpPacketTypeOffset) & KAvdtpPacketTypeMask) |
+ ((aMessageType<<KAvdtpMessageTypeOffset) & KAvdtpMessageTypeMask);
+
+ switch (aPacketType)
+ {
+ case ESingle:
+ {
+ header.SetLength(KAvdtpMinimumSignallingSinglePacketLength);
+ TUint8 lastByte = ((aSigId) & KAvdtpSignalIdentifierMask);
+ header.Put(firstByte,0);
+ header.Put(lastByte,1);
+ break;
+ }
+ case EStart:
+ {
+ header.SetLength(KAvdtpMinimumSignallingStartPacketLength);
+ TUint8 lastByte = ((aSigId) & KAvdtpSignalIdentifierMask);
+ header.Put(firstByte,0);
+ header.Put(static_cast<TUint8>(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<TAvdtpPacketType>((aFragment.First()->Ptr()[0] & KAvdtpPacketTypeMask) >> KAvdtpPacketTypeOffset);
+ TAvdtpMessageType messageType = static_cast<TAvdtpMessageType>((aFragment.First()->Ptr()[0] & KAvdtpMessageTypeMask) >> KAvdtpMessageTypeOffset);
+ TAvdtpTransactionLabel transactionLabel = static_cast<TAvdtpTransactionLabel>((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<TAvdtpMessage>(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<KAvdtpPacketSEPInfoSize> SEPInfoBuf;
+ SEPInfoBuf.SetMax();
+
+ SEPInfoBuf[0] = aSEPInfo.SEID().PacketValue();
+ if (aSEPInfo.InUse())
+ {
+ SEPInfoBuf[0]|=(1<<KAvdtpInUseFlagOffset);
+ }
+ SEPInfoBuf[1] = aSEPInfo.MediaType()<<KAvdtpMediaTypeOffset;
+ if (aSEPInfo.IsSink())
+ {
+ SEPInfoBuf[1]|=(1<<KAvdtpTSEPOffset);
+ }
+ AppendDataL(SEPInfoBuf);
+ }
+
+
+void CAvdtpOutboundSignallingMessage::AddSEPCapabilityL(const TAvdtpServiceCapability& aCapability)
+ {
+ LOG_FUNC
+ // append SEP capability to packet, this temp buffer *cannot* be placed on cleanupstack (it may get reallocated)
+ RBuf8 buf;
+ buf.CreateL(KAvdtpServiceCapabilitiesHeaderLen);
+ buf.CleanupClosePushL();
+ User::LeaveIfError(aCapability.AsProtocol(buf));
+ AppendDataL(buf);
+ buf.Close();
+ CleanupStack::Pop();
+ }
+
+void CAvdtpOutboundSignallingMessage::Deque()
+ {
+ LOG_FUNC
+ iLink.Deque();
+ }
+
+TInt CAvdtpOutboundSignallingMessage::AllocateTransactionLabel(TTransactionLabelManager& aManager)
+ {
+ LOG_FUNC
+ return aManager.GetLabel(iCommandLabel);
+ }
+
+void CAvdtpOutboundSignallingMessage::SetTransactionLabel(TAvdtpTransactionLabel aLabel)
+ {
+ LOG_FUNC
+ iResponseLabel = aLabel;
+ }
+
+TInt CAvdtpOutboundSignallingMessage::NewData(TUint /*aCount*/)
+ {
+ Panic(EAvdtpOutboundMessageNewDataCalled);
+ return KErrNotSupported;
+ }
+
+/**
+Upcall from signalling channel telling us of new inbound data
+The data is synchronously retrieved, checked and added to the building packet
+Once the packet is complete the packet begins parsing
+*/
+/*virtual*/ TInt CAvdtpInboundSignallingMessage::NewData(TUint aCount)
+ {
+ LOG_FUNC
+ RMBufChain fragment;
+ TInt result = KErrNone;
+
+ while (aCount--)
+ {
+ result = iSignallingChannel.GetData(fragment,NULL);
+
+ if (result<KErrNone)
+ {
+ break;
+ }
+
+ TAvdtpPacketType packetType;
+ TAvdtpMessageType messageType;
+ TAvdtpTransactionLabel transactionLabel;
+ // check the AVDTP Packet type part of the header
+ result = CheckPacketType(fragment, packetType, messageType, transactionLabel);
+
+ if (result == KErrAbort)
+ {
+ // if the packet build state is other than awaiting new then
+ // we have some existing data to throw out (the abort should discard)
+ if (iPacketBuildState != EAwaitingNew)
+ {
+ Data().Free(); //drop
+ }
+ // reset the packet build state so that we process the abort.
+ iPacketBuildState = EAwaitingNew;
+ // clear current message??
+ // at moment do nothing - mayneed to parse to see if it's the same SEID - yuk protocol
+ result = KErrNone; // will actually process the Abort message
+ }
+
+ // if the packet type is ok then it can be added into the building up packet
+ if (result == KErrNone)
+ {
+ iFragmentationInfo.iPacketNumber++;
+ // see whether to start new packet
+ switch (iPacketBuildState)
+ {
+ case EAwaitingNew:
+ // can see what this message is going to be
+ iMessageType = messageType;
+ TRAP(result,Data() = MessageL(fragment,packetType));
+
+ if (result==KErrNone)
+ {
+ iPacketBuildLabel = transactionLabel;
+ if (packetType==ESingle)
+ {
+ // and can now process - no more to wait for!
+ Process(iPacketBuildLabel);
+ // reset the packet number counter
+ iFragmentationInfo.iPacketNumber =0;
+ }
+ else
+ {
+ // a start, data remembered above, and hold off processing
+ iFragmentationInfo.iFragmented = ETrue;
+ iFragmentationInfo.iTotalPackets = NumberSignalPackets(fragment);
+ iPacketBuildState = EAwaitingContinue;
+ }
+ }
+ break;
+
+ case EAwaitingContinue:
+ {
+ // check that the number of packets < NOSP
+ result = iFragmentationInfo.iFragmented &&
+ (iFragmentationInfo.iPacketNumber < iFragmentationInfo.iTotalPackets)
+ ? KErrNone : KErrNotReady;
+
+ if (result==KErrNone)
+ {
+ RMBufChain message;
+ TRAP(result,message = MessageL(fragment,packetType));
+
+ if (result==KErrNone)
+ {
+ // add into forming packet
+ Data().Append(message);
+
+ // see if we expect End next
+ if (iFragmentationInfo.iPacketNumber == iFragmentationInfo.iTotalPackets-1)
+ {
+ iPacketBuildState = EAwaitingEnd;
+ }
+ }
+
+ }
+ }
+ break;
+ case EAwaitingEnd:
+ {
+ // check that the number of packets == NOSP
+ result = iFragmentationInfo.iFragmented &&
+ (iFragmentationInfo.iPacketNumber == iFragmentationInfo.iTotalPackets)
+ ? KErrNone : KErrNotReady;
+
+ if (result==KErrNone)
+ {
+ RMBufChain message;
+ TRAP(result,message = MessageL(fragment,packetType));
+ if (result==KErrNone)
+ {
+ // add into forming packet
+ Data().Append(message);
+ // and process cos no more to come
+ Process(iPacketBuildLabel);
+ iPacketBuildState = EAwaitingNew;
+ }
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ //drop - free'd below
+ }
+
+ // all done with the inbound fragment
+ fragment.Free();
+ }
+
+ return result;
+ }
+
+
+/**
+Begin processing the complete packet
+*/
+void CAvdtpInboundSignallingMessage::Process(TAvdtpTransactionLabel aLabel)
+ {
+ LOG_FUNC
+ iSignal = SignalIdentifier(Data());
+
+ // member function pointer
+ // the handlers have no policy - they just parse and generate indications to SAP
+ void (*handler)(CAvdtpInboundSignallingMessage&, TAvdtpTransactionLabel);
+
+ switch (Signal())
+ {
+ case EAvdtpDiscover:
+ handler = HandleDiscoverL;
+ break;
+ case EAvdtpGetCapabilities:
+ handler = HandleGetCapsL;
+ break;
+ case EAvdtpSetConfiguration:
+ handler = HandleSetConfigL;
+ break;
+ case EAvdtpGetConfiguration:
+ handler = HandleGetConfigL;
+ break;
+ case EAvdtpReconfigure:
+ handler = HandleReconfigL;
+ break;
+ case EAvdtpOpen:
+ handler = HandleOpenL;
+ break;
+ case EAvdtpStart:
+ handler = HandleStartL;
+ break;
+ case EAvdtpRelease:
+ handler = HandleReleaseL;
+ break;
+ case EAvdtpSuspend:
+ handler = HandleSuspendL;
+ break;
+ case EAvdtpAbort:
+ handler = HandleAbortL;
+ break;
+ case EAvdtpSecurityControl:
+ handler = HandleSecurityControlL;
+ break;
+ case EReserved:
+ Data().Free(); //drop
+ iPacketBuildState = EAwaitingNew;
+ return;
+ default:
+ {
+ if(iMessageType==ECommand)
+ {
+ iSignallingChannel.SendReject(aLabel, Signal(), EAvdtpNotSupportedCommand/*ignored*/);
+ }
+
+ Data().Free(); //drop
+ iPacketBuildState = EAwaitingNew;
+ return;
+ }
+ }
+ // trim off now-processed header stuff (that SigId)
+ Data().TrimStart(1);
+
+ // now invoke handler (via member function pointer)
+
+ TRAPD(parseError, (*handler)(*this, aLabel));
+
+ if (parseError != KErrNone && iMessageType==ECommand)
+ {
+ // kick the signalling channel to send appropriate error, but only for commands (responses are discarded)
+ // further the handlers need to take care - if they are supposed to send extended error info
+ // they cannot use this service
+ __ASSERT_DEBUG(Signal()!=EAvdtpSetConfiguration && Signal()!=EAvdtpReconfigure, Panic(EAvdtpSignallingMessageHandlerLeft));
+
+ switch(Signal())
+ {
+ case EAvdtpSetConfiguration:
+ {
+ iSignallingChannel.SendSetConfigurationReject(aLabel, AvdtpInternalUtils::SymbianErrorToAvdtpError(parseError), EServiceCategoryNull);
+ break;
+ }
+ case EAvdtpReconfigure:
+ {
+ iSignallingChannel.SendReconfigureReject(aLabel, AvdtpInternalUtils::SymbianErrorToAvdtpError(parseError), EServiceCategoryNull);
+ break;
+ }
+ default:
+ {
+ iSignallingChannel.SendReject(aLabel, Signal(), AvdtpInternalUtils::SymbianErrorToAvdtpError(parseError));
+ }
+ }
+ }
+
+ Data().Free(); //done parsing
+ iPacketBuildState = EAwaitingNew;
+ }
+
+void CAvdtpInboundSignallingMessage::DoHandleDiscoverL(TAvdtpTransactionLabel aLabel)
+ {
+ LOG_FUNC
+ switch (iMessageType)
+ {
+ case ECommand:
+ {
+ CheckPacketLengthL(KAvdtpDiscoverCommandMinimumLength, KAvdtpDiscoverCommandMaximumLength);
+ iSignallingChannel.DiscoverIndication(aLabel);
+ break;
+ }
+ case EResponseAccept:
+ {
+ TAvdtpInternalDiscoverConfirm cfm;
+
+ TInt err = CheckPacketLength(KAvdtpDiscoverAcceptMinimumLength, KAvdtpDiscoverAcceptMaximumLength);
+ if (Data().Length()%2!=0)
+ {
+ err = KErrCorrupt;
+ }
+ TInt numSEPs;
+ if (err==KErrNone)
+ {
+ const TInt KAvdtpDiscoverSEPLenOctets = 2;
+ numSEPs = (Data().Length())/KAvdtpDiscoverSEPLenOctets;
+ }
+ else
+ {
+ numSEPs = 0;
+ err = KErrNotFound;
+ }
+
+ if (numSEPs)
+ {
+ err = AvdtpSignallingMessageDiscover::Response::ParseL(Data(),
+ cfm.iDiscoveredSEPs,
+ iSignallingChannel.iProtocol.RemoteSEPCache(),
+ iSignallingChannel.RemoteAddress());
+ }
+
+ cfm.iResult = err;
+ cfm.iNumSEPs = numSEPs;
+ iSignallingChannel.DiscoverConfirm(aLabel, err, &cfm);
+ break;
+ }
+ case EResponseReject:
+ {
+ TInt err = CheckPacketLength(KAvdtpDiscoverRejectMinimumLength, KAvdtpDiscoverRejectMaximumLength);
+ err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(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<TAvdtpServiceCategory>(rejData[0]);
+ err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(rejData[1]));
+ }
+ iSignallingChannel.SetConfigConfirm(aLabel, err, cat);
+ break;
+ }
+ case EGeneralReject:
+ {
+ err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(Data().First()->Ptr()[0])) :
+ KErrCorrupt;
+ iSignallingChannel.GetConfigConfirm(aLabel,err);
+ break;
+ }
+ case EGeneralReject:
+ {
+ err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpServiceCategory>(rejData[0]);
+ err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(rejData[1]));
+ }
+ iSignallingChannel.ReconfigConfirm(aLabel, err, cat);
+ break;
+ }
+ case EGeneralReject:
+ {
+ TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(Data().First()->Ptr()[0])) :
+ KErrCorrupt;
+ iSignallingChannel.OpenConfirm(aLabel, err);
+ break;
+ }
+ case EGeneralReject:
+ {
+ TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<numSEIDs; i++)
+ {
+ iSignallingChannel.StartIndication(aLabel, LocalSEIDL());
+ Data().TrimStart(1);
+ }
+ }
+ break;
+ }
+ case EResponseAccept:
+ {
+ err = CheckPacketLength(KAvdtpStartAcceptMinimumLength, KAvdtpStartAcceptMaximumLength);
+ iSignallingChannel.StartConfirm(aLabel, err);
+ break;
+ }
+ case EResponseReject:
+ {
+ err = CheckPacketLength(KAvdtpStartRejectMinimumLength, KAvdtpStartRejectMaximumLength);
+ err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(Data().First()->Ptr()[0])) :
+ KErrCorrupt;
+ iSignallingChannel.ReleaseConfirm(aLabel, err);
+ break;
+ }
+ case EGeneralReject:
+ {
+ TInt err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<numSEIDs; i++)
+ {
+ iSignallingChannel.SuspendIndication(aLabel, LocalSEIDL());
+ Data().TrimStart(1);
+ }
+ }
+ break;
+ }
+ case EResponseAccept:
+ {
+ err = CheckPacketLength(KAvdtpSuspendAcceptMinimumLength, KAvdtpSuspendAcceptMaximumLength);
+ iSignallingChannel.SuspendConfirm(aLabel, err);
+ break;
+ }
+ case EResponseReject:
+ {
+ err = CheckPacketLength(KAvdtpSuspendRejectMinimumLength, KAvdtpSuspendRejectMaximumLength);
+ err = (err==KErrNone) ? SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(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<TAvdtpSignallingErrorCode>(Data().First()->Ptr()[0])) :
+ KErrCorrupt;
+ iSignallingChannel.SecurityControlConfirm(aLabel, err, KNullDesC8);
+ break;
+ }
+ case EGeneralReject:
+ {
+ err = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(static_cast<TAvdtpSignallingErrorCode>(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<TAvdtpMessage>(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 || pktLen<aMin)
+ {
+ ret = SymbianBluetoothAV::ConvertToSymbianError::AvdtpError(EAvdtpBadLength);
+ }
+ return ret;
+ }
+
+/*static*/
+TInt AvdtpSignallingMessageDiscover::Response::ParseL(const RMBufChain& aMessageData,
+ TDes8& aClientBuffer,
+ CRemoteSEPCache& aSEPCache,
+ const TBTDevAddr& aAddr)
+ {
+ LOG_STATIC_FUNC
+ aClientBuffer.Zero();
+
+ TInt numSEPs = (aMessageData.Length())/2;
+
+ __ASSERT_DEBUG(numSEPs, Panic(EAvdtpBadSEPCount)); // this should have been policed earlier
+
+ // initial checks
+ if (numSEPs>KMaxAvdtpNumSEPs)
+ {
+ return KErrCorrupt;
+ }
+
+ if (aClientBuffer.MaxLength()<(numSEPs*sizeof(TAvdtpSEPInfo)))
+ {
+ return KErrNoMemory;
+ }
+
+ // ok - parse
+ TInt err = KErrNone;
+
+ for (TInt i=0;i<=numSEPs-1;i++)
+ {
+ TBuf8<KAvdtpPacketSEPInfoSize> 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<SymbianBluetoothAV::TBluetoothMediaType>
+ (dataBuf[1]>>4));
+ sepInfo.SetIsSink((dataBuf[1] & 0x08) ? ETrue : EFalse);
+
+ err = aSEPCache.AddSEP(aAddr, sepInfo);
+
+ if (err==KErrNone)
+ {
+ TPckg<TAvdtpSEPInfo> 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);
+ }
+