// Copyright (c) 2005-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:///** @file @internalComponent*/#include <bluetooth/logger.h>#include <es_sock.h>#include "avctppacket.h"#include "avctpcommon.h"#include "avctpmuxer.h"#include "avctputils.h"#include "avctpconstants.h"#ifdef __FLOG_ACTIVE_LIT8(KLogComponent, LOG_COMPONENT_AVCTP);#endif#ifdef _DEBUGPANICCATEGORY("avctppkt");#endifusing namespace SymbianAvctp;/*static*/ TPtrC8 CAvctpPacket::GetHeader(const RMBufChain& aChain) { const RMBuf* mbuf = aChain.First(); // set the descriptor to read out the whole of the first mbuf (into which the header fits) return TPtrC8(mbuf->Ptr(), mbuf->Length()); }/**Fills in the TAvctpHeaderInfo This function takes a TAvctpStartHeaderInfo rather than a TAvctpHeaderInfo toavoid problems with casting from TAvctpHeaderInfo to TAvctpStartHeaderInfo & mangling data. @internalComponent @param aData The data buffer that contains the AVCTP packet to be parsed @param aHeaderInfo will contain the result of the parsing. @return KErrNone if there was no problem parsing the header, otherwise returns an Avctp specific error.*//*static*/ TInt CAvctpPacket::ParseHeader(const RMBufChain& aData, TAvctpStartHeaderInfo& aHeaderInfo) { LOG_STATIC_FUNC TInt err = KErrNone; // We require the packet to be long enough to at least contain the packet type const TPtrC8 dataP(GetHeader(aData)); if (dataP.Length() < EMinimumHeaderLength) { err = KErrPacketTooShort; } if (err == KErrNone) { aHeaderInfo.iMsgType = SymbianAvctp::MessageType(dataP); aHeaderInfo.iTransactionLabel = SymbianAvctp::TransactionLabel(dataP); } // No checking needs to be done on the TAvctpHeaderInfo variables since // all values are allowed. // get the packet type if (err == KErrNone) { aHeaderInfo.iPktType = SymbianAvctp::PacketType(dataP); switch (aHeaderInfo.iPktType) { case ENormalPkt: if (dataP.Length() < ENormalHeaderLength) { err = KErrPacketTooShort; } else { err = ParseNormalHeader(dataP, aHeaderInfo); } break; case EStartFrag: if (dataP.Length() < EStartFragHeaderLength) { err = KErrPacketTooShort; } else { err = ParseStartHeader(dataP, aHeaderInfo); } break; case EContinueFrag: case EEndFrag: // the Size check before this switch statement ensures that // the given data is long enough since EOtherFragHeaderLength = 1 break; default: err = KErrUnknownPacketType; break; } } return err; }/**Fills in the TAvctpNormalHeaderInfo Assumes aData is at least ENormalHeaderLength long @internalComponent @param aData The data buffer that contains the AVCTP packet to be parsed @param aHeaderInfo will contain the result of the parsing. @return KErrNone if there was no problem parsing the header, otherwise returns an Avctp specific error.*//*static*/ TInt CAvctpPacket::ParseNormalHeader(const TDesC8& aData, TAvctpNormalHeaderInfo& aHeaderInfo) { LOG_STATIC_FUNC aHeaderInfo.iHasValidPid = IsValidPid(aData); aHeaderInfo.iPid = Pid(aData); return CheckNormalHeaderInfo(aHeaderInfo); }/**Fills in the TAvctpStartHeaderInfo Assumes aData is at least EStartFragHeaderLength long @internalComponent @param aData The data buffer that contains the AVCTP packet to be parsed @param aHeaderInfo will contain the result of the parsing. @return KErrNone if there was no problem parsing the header, otherwise returns an Avctp specific error.*//*static*/ TInt CAvctpPacket::ParseStartHeader(const TDesC8& aData, TAvctpStartHeaderInfo& aHeaderInfo) { LOG_STATIC_FUNC TInt err = ParseNormalHeader(aData, aHeaderInfo); if (err == KErrNone) { aHeaderInfo.iFragmentsInSdu = FragmentsInSdu(aData); err = CheckStartHeaderInfo(aHeaderInfo); } return err; }/*Checks the validity of a TAvctpNormalHeaderInfo object. Note that the variablesderived from TAvctpHeaderInfo cannot be incorrect since all values that might appearin a air packet are allowed.(NB the RFA field in Continue and End packets [the IPID field in other types of packet]must be set to 0 in the AVCTP v1.0 spec. However, we don't enforce this on incomingin case it is used in future.)*/ /*static*/ TInt CAvctpPacket::CheckNormalHeaderInfo(const TAvctpNormalHeaderInfo& aHeaderInfo) { LOG_STATIC_FUNC ASSERT_DEBUG(aHeaderInfo.iPktType == ENormalPkt || aHeaderInfo.iPktType == EStartFrag); TInt ret = KErrNone; if (!aHeaderInfo.iHasValidPid && aHeaderInfo.iMsgType == ECommand) { ret = KErrMalformedPacketFromRemote; } return ret; }/*Checks the validity of a TAvctpStartHeaderInfo object. */ /*static*/ TInt CAvctpPacket::CheckStartHeaderInfo(const TAvctpStartHeaderInfo& aHeaderInfo) { LOG_STATIC_FUNC ASSERT_DEBUG(aHeaderInfo.iPktType == EStartFrag); TInt ret = KErrNone; if (aHeaderInfo.iFragmentsInSdu > 1) { ret = CheckNormalHeaderInfo(aHeaderInfo); } else { ret = KErrMalformedPacketFromRemote; } return ret; }//// //// HAvctpOutgoingSdu Implementation //// ////HAvctpOutgoingSdu* HAvctpOutgoingSdu::NewL(const TAvctpNormalHeaderInfo& aHeaderInfo, const TBTDevAddr& aAddr, RMBufChain& aData) { LOG_STATIC_FUNC HAvctpOutgoingSdu* sdu = new(ELeave) HAvctpOutgoingSdu(aHeaderInfo, aAddr); CleanupStack::PushL(sdu); sdu->ConstructL(aData); CleanupStack::Pop(sdu); return sdu; }/** Create the buffer by copying over the other descriptor allowing space for a headerat the beginning*/ void HAvctpOutgoingSdu::ConstructL(RMBufChain& aData) { LOG_FUNC iSduData.Assign(aData); }HAvctpOutgoingSdu* HAvctpOutgoingSdu::NewIpidResponseL(const HAvctpIncomingSdu& aIncomingSdu, TInt aChannel) { LOG_STATIC_FUNC TPtrC8 hdr(CAvctpPacket::GetHeader(aIncomingSdu.Data())); LOG1(_L("to Pid 0x%x"), Pid(hdr)); TAvctpNormalHeaderInfo headerInfo = TAvctpNormalHeaderInfo(TransactionLabel(hdr), ENormalPkt, EResponse, EFalse, Pid(hdr) ); HAvctpOutgoingSdu* sdu = new(ELeave) HAvctpOutgoingSdu(headerInfo, aIncomingSdu.BTAddr()); sdu->iChannel = aChannel; return sdu; }HAvctpOutgoingSdu::~HAvctpOutgoingSdu() { LOG_FUNC iSduData.Free(); if (iOutboundQ) { iOutboundQ->Deque(*this); } else { iQueLink.Deque(); } }