bluetooth/btstack/avctp/avctppacket.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avctp/avctppacket.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,279 @@
+// 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 _DEBUG
+PANICCATEGORY("avctppkt");
+#endif
+
+using 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 to
+avoid 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 variables
+derived from TAvctpHeaderInfo cannot be incorrect since all values that might appear
+in 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 incoming
+in 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 header
+at 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();	
+		}
+	}
+
+