bluetooth/btstack/avctp/avctpPacketMgr.cpp
changeset 0 29b1cd4cb562
child 23 5b153be919d4
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <bluetooth/logger.h>
       
    22 #include <bluetoothav.h>
       
    23 #include <es_mbuf.h>
       
    24 
       
    25 #include "avctpPacketMgr.h" 
       
    26 #include "Avctp.h"
       
    27 #include "avctpmuxer.h"
       
    28 #include "avctpconstants.h"
       
    29 
       
    30 #ifdef __FLOG_ACTIVE
       
    31 _LIT8(KLogComponent, LOG_COMPONENT_AVCTP);
       
    32 #endif
       
    33 
       
    34 #ifdef _DEBUG
       
    35 PANICCATEGORY("pktmgr");
       
    36 #endif
       
    37 
       
    38 using namespace SymbianAvctp;
       
    39 
       
    40 /**
       
    41 Static factory function for an AVCTP Packet Manager
       
    42 
       
    43   @internalComponent
       
    44   @leave KErrNoMemory if the new packet could not be allocated
       
    45   @return A pointer to an AVCTP Packet Manager
       
    46 */
       
    47 CAvctpPacketMgr* CAvctpPacketMgr::NewL(CAvctpTransport& aMuxer,
       
    48 										CAvctpProtocol& aProtocol)
       
    49 	{
       
    50 	LOG_STATIC_FUNC
       
    51 	CAvctpPacketMgr* mgr = new(ELeave) CAvctpPacketMgr(aMuxer, aProtocol);
       
    52 	CleanupStack::PushL(mgr);
       
    53 	mgr->ConstructL();
       
    54 	CleanupStack::Pop(mgr);
       
    55 	return mgr;	
       
    56 	}
       
    57 
       
    58 void CAvctpPacketMgr::ConstructL()
       
    59 	{
       
    60 	LOG_FUNC
       
    61 	iIncomingAssemblers[KAvctpPrimaryChannel] = CIncomingSduAssembler::NewL(*this,0);
       
    62 	iOutgoingFragmenters[KAvctpPrimaryChannel] = COutgoingSduFragmenter::NewL(*this,0);	
       
    63 	iIncomingAssemblers[KAvctpSecondaryChannel] = CIncomingSduAssembler::NewL(*this,1);
       
    64 	iOutgoingFragmenters[KAvctpSecondaryChannel] = COutgoingSduFragmenter::NewL(*this,1);	
       
    65 	}
       
    66 
       
    67 /**
       
    68 Default constructor for an AVCTP Packet Manager
       
    69 
       
    70   @internalComponent
       
    71 */
       
    72 CAvctpPacketMgr::CAvctpPacketMgr(CAvctpTransport& aTransport, CAvctpProtocol& aProtocol)
       
    73 	: iTransport(aTransport),
       
    74 	  iProtocol(aProtocol)
       
    75 	{
       
    76 	LOG_FUNC
       
    77 	}
       
    78 
       
    79 /**
       
    80 Default destructor for an AVCTP Packet Manager
       
    81 
       
    82   @internalComponent
       
    83 */
       
    84 CAvctpPacketMgr::~CAvctpPacketMgr()
       
    85 	{
       
    86 	LOG_FUNC
       
    87 	
       
    88 	delete iIncomingAssemblers[0];
       
    89 	delete iOutgoingFragmenters[0];
       
    90 	delete iIncomingAssemblers[1];
       
    91 	delete iOutgoingFragmenters[1];
       
    92 	}
       
    93 
       
    94 /**
       
    95 Transfers ownership of the aOutgoingSdu to CAvctpPacketMgr if the write succeeded
       
    96 i.e. didn't return 0
       
    97 
       
    98 Note this function should not be used by other classes to send IPID responses. 
       
    99 Use WriteIpid for this instead.
       
   100 */
       
   101 void CAvctpPacketMgr::Write(HAvctpOutgoingSdu*& aOutgoingSdu, TInt aChannel)
       
   102 	{
       
   103 	LOG_FUNC
       
   104 	
       
   105 	iOutgoingFragmenters[aChannel]->Write(aOutgoingSdu);
       
   106 	}
       
   107 	
       
   108 /**
       
   109 This functions
       
   110 
       
   111 Transfers ownership of the aOutgoingSdu to CAvctpPacketMgr if the write succeeded
       
   112 i.e. didn't return 0
       
   113 
       
   114 Note this function should only be used to send IPID responses. Use Write for all other
       
   115 Sdus instead.
       
   116 */
       
   117 TInt CAvctpPacketMgr::WriteIpid(HAvctpOutgoingSdu*& aOutgoingSdu)
       
   118 	{
       
   119 	LOG_FUNC
       
   120 	
       
   121 	Write(aOutgoingSdu, aOutgoingSdu->Channel());
       
   122 	
       
   123 	TInt ret = KErrNone;
       
   124 	if (!aOutgoingSdu)
       
   125 		{
       
   126 		++iIpidSdusSent;
       
   127 		LOG1(_L("Sent %d IPID responses"), iIpidSdusSent);
       
   128 		if (iIpidSdusSent >= KMaximumIpidResponsesAllowed)
       
   129 			{
       
   130 			ret = KErrRemoteSentTooManyIpidSdus;
       
   131 			}
       
   132 		}
       
   133 	else
       
   134 		{
       
   135 		ret = KErrMuxerBlocked;	// if the sdu is not null means it hasn't been sent.
       
   136 		}
       
   137 	return ret;
       
   138 	}
       
   139 	
       
   140 /** 
       
   141 This is the lower protocol notifying us it can now send more data
       
   142 We check to see if we were in the middle of sending fragments and
       
   143 if so we write all those we can.
       
   144 @return EFalse if we've blocked the muxer o/w EFalse
       
   145 */
       
   146 void CAvctpPacketMgr::CanSend(TInt aChannel)
       
   147 	{
       
   148 	LOG_FUNC
       
   149 
       
   150 	iOutgoingFragmenters[aChannel]->CanSend();
       
   151 	}
       
   152 
       
   153 /**
       
   154 We don't pass on the send / recv errors to the saps
       
   155 because these errors only concern the packets we've
       
   156 tried to send over L2CAP.
       
   157 
       
   158 We don't do anything on fatal errors cause the muxer 
       
   159 goes down in that situation and takes the packet mgr
       
   160 with it.
       
   161 */
       
   162 void CAvctpPacketMgr::SignalMuxerError(TInt /*aError*/,TUint aOperationMask)
       
   163 	{
       
   164 	LOG_FUNC
       
   165 
       
   166 	if (aOperationMask & (MSocketNotify::EErrorSend))
       
   167 		{
       
   168 		iIncomingAssemblers[KAvctpPrimaryChannel]->Reset();
       
   169 		iIncomingAssemblers[KAvctpSecondaryChannel]->Reset();
       
   170 		}
       
   171 	
       
   172 	if (aOperationMask & (MSocketNotify::EErrorRecv))
       
   173 		{
       
   174 		iOutgoingFragmenters[KAvctpPrimaryChannel]->Reset();
       
   175 		iOutgoingFragmenters[KAvctpSecondaryChannel]->Reset();
       
   176 		}
       
   177 	}
       
   178 	
       
   179 /**
       
   180 This function transfers the ownership of aIncomingPdu from the
       
   181 muxer to CAvctpPacketMgr
       
   182 */ 
       
   183 TInt CAvctpPacketMgr::NewData(RMBufChain& aIncomingPdu, TInt aChannel)
       
   184 	{
       
   185 	LOG_FUNC
       
   186 
       
   187 	TAvctpStartHeaderInfo headerInfo;
       
   188 	TInt err = CAvctpPacket::ParseHeader(aIncomingPdu, headerInfo);
       
   189 	if (err == KErrNone)
       
   190 		{
       
   191 		TRAP(err, iIncomingAssemblers[aChannel]->AddDataL(headerInfo, aIncomingPdu)); // transfers ownership of aIncomingPdu on success 
       
   192 		if (err != KErrNone)
       
   193 			{
       
   194 			// We've OOM'd so drop packet
       
   195 			aIncomingPdu.Free();
       
   196 			
       
   197 			// Don't reset iIncomingAssembler since it'll reset itself on 
       
   198 			// the next start or normal packet if we missed a vital fragment here
       
   199 			}
       
   200 			
       
   201 		err=KErrNone; //Want to read remaining packets, so don't pass an error back up.
       
   202 		}
       
   203 	else
       
   204 		{
       
   205 		// There was something wrong with the PDU so punish the remote
       
   206 		Transport().Shutdown(err);
       
   207 		aIncomingPdu.Free();
       
   208 		err = KErrMuxerShutDown;
       
   209 		}
       
   210 		
       
   211 	return err;
       
   212 	}
       
   213 
       
   214 TBool CAvctpPacketMgr::WouldLikeToSend()
       
   215 	{
       
   216 	return iOutgoingFragmenters[KAvctpPrimaryChannel]->HasData() || iOutgoingFragmenters[KAvctpSecondaryChannel]->HasData();  
       
   217 	}
       
   218 	
       
   219 //
       
   220 //
       
   221 // implementation of COutgoingSduFragmenter
       
   222 //
       
   223 //
       
   224 
       
   225 /**
       
   226 Default constructor for an outgoing partial AVCTP Sdu
       
   227   @internalComponent
       
   228 */
       
   229 COutgoingSduFragmenter::COutgoingSduFragmenter(CAvctpPacketMgr& aMgr, TInt aChannel)
       
   230 	: iMgr(aMgr), iChannel(aChannel)
       
   231 	{
       
   232 	LOG_FUNC
       
   233 
       
   234 	}
       
   235 
       
   236 /**
       
   237 Static factory function
       
   238 
       
   239   @internalComponent
       
   240   @leave KErrNoMemory if the new packet could not be allocated
       
   241   @return A pointer to an outgoing partial AVCTP Sdu
       
   242 */
       
   243 COutgoingSduFragmenter* COutgoingSduFragmenter::NewL(CAvctpPacketMgr& aMgr, TInt aChannel)
       
   244 	{
       
   245 	LOG_STATIC_FUNC
       
   246 
       
   247 	COutgoingSduFragmenter* packet = new(ELeave) COutgoingSduFragmenter(aMgr, aChannel);
       
   248 	CleanupStack::PushL(packet);
       
   249 	packet->ConstructL();
       
   250 	CleanupStack::Pop(packet);
       
   251 	return packet;
       
   252 	}	
       
   253 
       
   254 void COutgoingSduFragmenter::ConstructL()
       
   255 	{
       
   256 	LOG_FUNC
       
   257 	
       
   258 	TCallBack cb(SendAsyncCallBack, this);
       
   259 	iSendAsyncCallBack = new(ELeave) CAsyncCallBack(cb, EActiveHighPriority);
       
   260 	}
       
   261 
       
   262 COutgoingSduFragmenter::~COutgoingSduFragmenter()
       
   263 	{
       
   264 	LOG_FUNC
       
   265 
       
   266 	delete iSendAsyncCallBack;
       
   267 	}	
       
   268 	
       
   269 void COutgoingSduFragmenter::Reset()
       
   270 	{
       
   271 	LOG_FUNC
       
   272 
       
   273 	iSduData.Free();
       
   274 	iCurrentWriteState = ENormal;
       
   275 	// we don't have anymore data to send, so check for idle so that if the transport is idle, the 
       
   276 	// timer will be set and when expires it will be destroyed.
       
   277 	iMgr.Transport().CheckForIdle();
       
   278 	}
       
   279 
       
   280 TBool COutgoingSduFragmenter::HasData()
       
   281 	{
       
   282 	return iSduData.Length() > 0;
       
   283 	}
       
   284 
       
   285 /**
       
   286 If we can take ownership of this we do, and kick off async send.  Otherwise
       
   287 we do nothing and the SDU remains on the caller's queue.
       
   288 */
       
   289 void COutgoingSduFragmenter::Write(HAvctpOutgoingSdu*& aOutgoingSdu)
       
   290 	{
       
   291 	LOG_FUNC
       
   292 
       
   293 	if (iSduData.Length() == 0)
       
   294 		{
       
   295 		iSduData.Assign(aOutgoingSdu->Data());
       
   296 		iAddr = aOutgoingSdu->BTAddr();
       
   297 		iHeaderInfo = aOutgoingSdu->HeaderInfo();
       
   298 		
       
   299 		delete aOutgoingSdu;
       
   300 		aOutgoingSdu = NULL;
       
   301 
       
   302 		StartSendAsyncCallBack();
       
   303 		}
       
   304 	}
       
   305 
       
   306 TInt COutgoingSduFragmenter::CountFragments(const RMBufChain& aSdu, TInt iMtuUsedToFragment) const
       
   307 	{
       
   308 	TUint totalFragmentsNeeded = 1;
       
   309 	if (aSdu.Length() + ENormalHeaderLength > iMtuUsedToFragment)
       
   310 		{
       
   311 		TInt dataRemaining = aSdu.Length() + EStartFragHeaderLength
       
   312 									 - iMtuUsedToFragment;
       
   313 		while (dataRemaining > 0)
       
   314 			{
       
   315 			totalFragmentsNeeded++;
       
   316 			dataRemaining -= (iMtuUsedToFragment - EOtherFragHeaderLength);
       
   317 			}
       
   318 		}
       
   319 	return totalFragmentsNeeded;
       
   320 	}
       
   321 
       
   322 void COutgoingSduFragmenter::DoSendCurrentSDU()
       
   323 	{
       
   324 	// we should have one fragmenter allowed to write to a given remote at any time
       
   325 	// once the fragmenter has done its job then we can ask the SAPs to drain an SDU into the fragger
       
   326 	TInt mtu = iMgr.Transport().GetCurrentOutboundMtu(iChannel);
       
   327 	
       
   328 	// If we couldn't retrieve the MTU we aren't in a state where we can send.
       
   329 	// Once we are send should be kicked off by mux calling CanSend().
       
   330 	if(mtu > 0)
       
   331 		{
       
   332 		switch(iCurrentWriteState)
       
   333 			{
       
   334 			case ENormal:
       
   335 				{
       
   336 				BeginSendingSdu(mtu);
       
   337 				break;
       
   338 				}
       
   339 			case EFragmenting:
       
   340 				{
       
   341 				ContinueSendingSdu(mtu);
       
   342 				break;
       
   343 				}
       
   344 			default:
       
   345 				__ASSERT_DEBUG(EFalse, Panic(EAvctpInvalidFragmenterState));
       
   346 			};
       
   347 		}
       
   348 	}
       
   349 
       
   350 void COutgoingSduFragmenter::BeginSendingSdu(TInt aMtu)
       
   351 	{
       
   352 	LOG_FUNC
       
   353 	
       
   354 	__ASSERT_DEBUG(iCurrentWriteState == COutgoingSduFragmenter::ENormal, Panic(EAvctpInvalidFragmenterState));
       
   355 
       
   356 	RMBufChain pdu;
       
   357 	TInt numberFragments = 1;
       
   358 	
       
   359 	if (aMtu >= iSduData.Length() + ENormalHeaderLength)
       
   360 		{
       
   361 		pdu.Assign(iSduData);
       
   362 		}
       
   363 	else
       
   364 		{
       
   365 		numberFragments = CountFragments(iSduData, aMtu);
       
   366 		pdu.Assign(iSduData);
       
   367 		
       
   368 		__DEBUG_ONLY(TInt err =) pdu.Split(aMtu - EStartFragHeaderLength, iSduData);
       
   369 		__ASSERT_DEBUG(err==KErrNone, Panic(EAvctpRMBufChainSplitError));
       
   370 		}
       
   371 
       
   372 	iHeaderInfo.iPktType = (iSduData.Length()) ? EStartFrag : ENormalPkt;
       
   373 
       
   374 	if (AddHeader(pdu, numberFragments) == KErrNone)
       
   375 		{
       
   376 		if (iMgr.Transport().DoWrite(pdu,iChannel))
       
   377 			{
       
   378 			if(iSduData.Length() == 0)
       
   379 				{
       
   380 				Reset();
       
   381 				}
       
   382 			else
       
   383 				{
       
   384 				iCurrentWriteState = COutgoingSduFragmenter::EFragmenting;
       
   385 				}
       
   386 			
       
   387 			CheckForCanSend();
       
   388 			}
       
   389 		else
       
   390 			{
       
   391 			pdu.Remove();	// remove the first RMBuf (that is the header)
       
   392 			iSduData.Prepend(pdu); // put back the pdu in the iSduData
       
   393 			}
       
   394 		}
       
   395 	else
       
   396 		{
       
   397 		LOG(_L("Error creating the header because KErrNoMemory"));
       
   398 		__ASSERT_DEBUG(!pdu.IsEmpty(), Panic(EAvctpFragmenterEmptyPdu));
       
   399 		pdu.Free();
       
   400 		Reset();
       
   401 		}
       
   402 	__ASSERT_DEBUG(pdu.IsEmpty(), Panic(EAvctpFragmenterNonEmptyPdu));
       
   403 	}
       
   404 
       
   405 void COutgoingSduFragmenter::ContinueSendingSdu(TInt aMtu)
       
   406 	{
       
   407 	RMBufChain pdu;
       
   408 	// if the data payload plus the header fit in the mtu then we can send all the iSduData content 
       
   409 	if (aMtu >= iSduData.Length() + EOtherFragHeaderLength)
       
   410 		{
       
   411 		pdu.Assign(iSduData);
       
   412 		}
       
   413 	// we need to split iSduData as it is bigger than the mtu
       
   414 	else
       
   415 		{
       
   416 		pdu.Assign(iSduData);
       
   417 		
       
   418 		__DEBUG_ONLY(TInt err =) pdu.Split(aMtu - EOtherFragHeaderLength, iSduData);
       
   419 		__ASSERT_DEBUG(err==KErrNone, Panic(EAvctpRMBufChainSplitError));
       
   420 		}
       
   421 
       
   422 	// pdu now containts either the whole remainend sdu data (first if branch) or a bit of it (second branch)
       
   423 	// and iSduData contains either nothing or the remained sdu payload. Based on its length we know the packet type
       
   424 	// we are going to send.
       
   425 	iHeaderInfo.iPktType = (iSduData.Length()) ? EContinueFrag : EEndFrag;
       
   426 
       
   427 	if (AddHeader(pdu, 1) == KErrNone)
       
   428 		{
       
   429 		if (iMgr.Transport().DoWrite(pdu,iChannel))
       
   430 			{
       
   431 			if(iSduData.Length() == 0)
       
   432 				{
       
   433 				Reset();
       
   434 				}
       
   435 			
       
   436 			CheckForCanSend();
       
   437 			}
       
   438 		else
       
   439 			{
       
   440 			pdu.Remove();	// remove the first RMBuf (that is the header)
       
   441 			iSduData.Prepend(pdu); // put back the pdu in the iSduData
       
   442 			}
       
   443 		}
       
   444 	else
       
   445 		{
       
   446 		LOG(_L("Error creating the header because KErrNoMemory"));
       
   447 		__ASSERT_DEBUG(!pdu.IsEmpty(), Panic(EAvctpFragmenterEmptyPdu));
       
   448 		pdu.Free();
       
   449 		Reset();
       
   450 		}
       
   451 	__ASSERT_DEBUG(pdu.IsEmpty(), Panic(EAvctpFragmenterNonEmptyPdu));
       
   452 	}
       
   453 	
       
   454 TInt COutgoingSduFragmenter::AddHeader(RMBufChain& aPdu, TInt aNumFragments)
       
   455 	{
       
   456 	TInt headerLength = 0;
       
   457 	switch(iHeaderInfo.iPktType)
       
   458 		{
       
   459 		case ENormalPkt:
       
   460 			headerLength = ENormalHeaderLength;
       
   461 			break;
       
   462 		case EStartFrag:
       
   463 			headerLength = EStartFragHeaderLength;
       
   464 			break;
       
   465 		case EContinueFrag:
       
   466 		case EEndFrag:
       
   467 			headerLength = EOtherFragHeaderLength;
       
   468 			break;
       
   469 		default:
       
   470 			__ASSERT_DEBUG(EFalse, Panic(EAvctpFragmenterInvalidHeaderType));
       
   471 		}
       
   472 	
       
   473 	RMBuf* header = RMBuf::Alloc(headerLength);
       
   474 	if (header)
       
   475 		{
       
   476 		TUint8& avctpHeaderByte = *(header->Ptr());
       
   477 		avctpHeaderByte = 0;
       
   478 	
       
   479 		// Check the transaction label is valid
       
   480 		AssertValidTransactionLabel(iHeaderInfo.iTransactionLabel);
       
   481 	
       
   482 		avctpHeaderByte |= iHeaderInfo.iTransactionLabel << KTransactionLabelShift;
       
   483 		avctpHeaderByte |= iHeaderInfo.iPktType << KPacketTypeShift;
       
   484 			
       
   485 		if (iHeaderInfo.iMsgType == SymbianAvctp::EResponse)
       
   486 			{
       
   487 			avctpHeaderByte |= KResponseMsgBit;
       
   488 			}
       
   489 		
       
   490 		if(iHeaderInfo.iPktType == ENormalPkt)
       
   491 			{
       
   492 			BigEndian::Put16(header->Ptr()+KNormalHeaderPidOffset,iHeaderInfo.iPid);
       
   493 			}
       
   494 		else if(iHeaderInfo.iPktType == EStartFrag)
       
   495 			{
       
   496 			*(header->Ptr() + KNumFragmentsOffset) = aNumFragments;
       
   497 			BigEndian::Put16(header->Ptr()+KStartHeaderPidOffset,iHeaderInfo.iPid);
       
   498 			}
       
   499 		
       
   500 		if (!iHeaderInfo.iHasValidPid)
       
   501 			{
       
   502 			avctpHeaderByte |= KIsValidPidMask;
       
   503 			}
       
   504 		
       
   505 		aPdu.Prepend(header);
       
   506 		}
       
   507 	
       
   508 	return header ? KErrNone : KErrNoMemory;
       
   509 	}
       
   510 
       
   511 void COutgoingSduFragmenter::CanSend()
       
   512 	{
       
   513 	LOG_FUNC
       
   514 
       
   515 	// If we have Sdu left to send this will kick off an async send, else
       
   516 	// it will signal to SAPs that we are ready to receive more data
       
   517 	CheckForCanSend();
       
   518 	}
       
   519 
       
   520 /*static*/ TInt COutgoingSduFragmenter::SendAsyncCallBack(TAny* aFragmenter)
       
   521 	{
       
   522 	static_cast<COutgoingSduFragmenter*>(aFragmenter)->DoSendCurrentSDU();
       
   523 	return KErrNone;
       
   524 	}
       
   525 
       
   526 
       
   527 void COutgoingSduFragmenter::StartSendAsyncCallBack()
       
   528 	{
       
   529 	iSendAsyncCallBack->CallBack();
       
   530 	}
       
   531 
       
   532 void COutgoingSduFragmenter::CancelSendAsyncCallBack()
       
   533 	{
       
   534 	iSendAsyncCallBack->Cancel();
       
   535 	}
       
   536 
       
   537 void COutgoingSduFragmenter::CheckForCanSend()
       
   538 	{
       
   539 	LOG_FUNC
       
   540 
       
   541 	if (iSduData.Length())
       
   542 		{
       
   543 		StartSendAsyncCallBack();
       
   544 		}
       
   545 	else
       
   546 		{	
       
   547 		// Only signal CanSend to the saps if we haven't got any
       
   548 		// fragments left to send
       
   549 		iMgr.Protocol().SignalCanSendToSaps(iMgr);		
       
   550 		}
       
   551 	}
       
   552 
       
   553 //
       
   554 //
       
   555 // implementation of CIncomingSduAssembler
       
   556 //
       
   557 //
       
   558 
       
   559 /**
       
   560 Default constructor for an incoming partial AVCTP Sdu
       
   561 
       
   562   @internalComponent
       
   563 */
       
   564 CIncomingSduAssembler::CIncomingSduAssembler(CAvctpPacketMgr& aMgr, TInt aChannel)
       
   565 	: iMgr(aMgr), iChannel(aChannel)
       
   566 	{
       
   567 	LOG_FUNC
       
   568 	}
       
   569 
       
   570 /**
       
   571 Static factory function
       
   572 
       
   573   @internalComponent
       
   574   @leave KErrNoMemory if the new packet could not be allocated
       
   575   @return A pointer to an incoming partial AVCTP Sdu
       
   576  */
       
   577 CIncomingSduAssembler* CIncomingSduAssembler::NewL(CAvctpPacketMgr& aMgr, TInt aChannel)
       
   578 	{
       
   579 	LOG_STATIC_FUNC
       
   580 
       
   581 	CIncomingSduAssembler* assembler = new(ELeave) CIncomingSduAssembler(aMgr, aChannel);
       
   582 	CleanupStack::PushL(assembler);
       
   583 	assembler->ConstructL();
       
   584 	CleanupStack::Pop(assembler);
       
   585 	return assembler;
       
   586 	}	
       
   587 
       
   588 void CIncomingSduAssembler::ConstructL()
       
   589 	{
       
   590 	LOG_FUNC
       
   591 
       
   592 	// chain member just takes ownership of stuff from l2cap
       
   593 	}
       
   594 
       
   595 CIncomingSduAssembler::~CIncomingSduAssembler()
       
   596 	{
       
   597 	LOG_FUNC
       
   598 
       
   599 	iAccretingSdu.Free();
       
   600 	}
       
   601 
       
   602 void CIncomingSduAssembler::Reset()
       
   603 	{
       
   604 	LOG_FUNC
       
   605 
       
   606 	iStartHeaderInfo = *new (&iStartHeaderInfo) TAvctpStartHeaderInfo;
       
   607 	iFragmentsReceived = 0;
       
   608 	iContinueFragmentSize = 0;
       
   609 	iAccretingSdu.Free();
       
   610 	}
       
   611 	
       
   612 /**
       
   613 This function transfers the ownership of aIncomingPdu to CIncomingSduAssembler.
       
   614 aIncomingPdu will represent a valid PDU as described by TAvctpStartHeaderInfo
       
   615 */
       
   616 void CIncomingSduAssembler::AddDataL(TAvctpStartHeaderInfo& aHeaderInfo, 
       
   617 									RMBufChain& aIncomingPdu)
       
   618 	{
       
   619 	LOG_FUNC
       
   620 
       
   621 	switch (aHeaderInfo.iPktType)
       
   622 		{
       
   623 		case ENormalPkt:
       
   624 			ProcessNormalPduL(aIncomingPdu);
       
   625 			break;
       
   626 		case EStartFrag:
       
   627 			ProcessStartPdu(aHeaderInfo, aIncomingPdu);
       
   628 			break;
       
   629 			
       
   630 		case EContinueFrag:
       
   631 			ProcessContinuePdu(aHeaderInfo, aIncomingPdu);
       
   632 			break;
       
   633 			
       
   634 		case EEndFrag:
       
   635 			ProcessEndPduL(aHeaderInfo, aIncomingPdu);
       
   636 			break;
       
   637 			
       
   638 		default:
       
   639 			Panic(EUnknownPacketType);
       
   640 		}	
       
   641 	}
       
   642 /**
       
   643 Because fragments in the same SDU can't be interleaved, this functions throws away any existing 
       
   644 partial SDU
       
   645 */	
       
   646 void CIncomingSduAssembler::ProcessNormalPduL(RMBufChain& aIncomingPdu)
       
   647 	{
       
   648 	LOG_FUNC
       
   649 
       
   650 	HAvctpIncomingSdu* sdu = new (ELeave) HAvctpIncomingSdu(iMgr.DevAddr(), aIncomingPdu);
       
   651 
       
   652 	iMgr.Protocol().SignalNewDataToSaps(sdu, iChannel); // transfers ownership of iAccretingSdu data via the HAvctpIncomingSdu
       
   653 	Reset(); 
       
   654 	}
       
   655 	
       
   656 /**
       
   657 Because fragments in the same SDU can't be interleaved, this functions throws away any existing 
       
   658 partial SDU
       
   659 */
       
   660 void CIncomingSduAssembler::ProcessStartPdu(TAvctpStartHeaderInfo& aHeaderInfo, RMBufChain& aIncomingPdu)
       
   661 	{
       
   662 	LOG_FUNC
       
   663 	
       
   664 	iStartHeaderInfo.iPktType = EStartFrag;	 //Not sure we want to bother updating this during aggregation
       
   665 	iStartHeaderInfo.iFragmentsInSdu = aHeaderInfo.iFragmentsInSdu;
       
   666 	iStartHeaderInfo.iTransactionLabel = aHeaderInfo.iTransactionLabel;
       
   667 	iStartHeaderInfo.iMsgType = aHeaderInfo.iMsgType;
       
   668 	iFragmentsReceived = 1;
       
   669 	iContinueFragmentSize = aIncomingPdu.Length();
       
   670 	
       
   671 	// All packets we pass up to AVCTPServices have the same header format.
       
   672 	// Because fragmentation happens transparently to the client side we 
       
   673 	// present all packets with a normal header.
       
   674 	TUint8 headerByte = *(aIncomingPdu.First()->Ptr());
       
   675 	aIncomingPdu.TrimStart(1);
       
   676 	*(aIncomingPdu.First()->Ptr()) = headerByte & KAvctpNormalHeaderMask;
       
   677 	
       
   678 	iAccretingSdu.Free();
       
   679 	iAccretingSdu.Assign(aIncomingPdu);
       
   680 	}
       
   681 	
       
   682 void CIncomingSduAssembler::ProcessContinuePdu(const TAvctpStartHeaderInfo& aHeaderInfo,
       
   683 												RMBufChain& aIncomingPdu)
       
   684 	{
       
   685 	LOG_FUNC
       
   686 	if (iAccretingSdu.Length() &&
       
   687 			iStartHeaderInfo.iTransactionLabel == aHeaderInfo.iTransactionLabel)
       
   688 		{
       
   689 		// the end packet matches by label - good!
       
   690 		if (iFragmentsReceived < iStartHeaderInfo.iFragmentsInSdu -1 && // not <= since we expect a End Fragment at least after a Continue
       
   691 			iStartHeaderInfo.iMsgType == aHeaderInfo.iMsgType &&		
       
   692 			aIncomingPdu.Length() <= iContinueFragmentSize)			
       
   693 			{
       
   694 			iFragmentsReceived++;
       
   695 			aIncomingPdu.TrimStart(EOtherFragHeaderLength);
       
   696 			iAccretingSdu.Append(aIncomingPdu);
       
   697 			}
       
   698 		else if (iFragmentsReceived    >= iStartHeaderInfo.iFragmentsInSdu - 1 || // - 1 cause we've not counted this packet yet
       
   699 				 aIncomingPdu.Length() != iContinueFragmentSize ||
       
   700 				 iStartHeaderInfo.iMsgType != aHeaderInfo.iMsgType)
       
   701 				  
       
   702 			{
       
   703 			iMgr.Transport().Shutdown(KErrMalformedPacketFromRemote);
       
   704 			Reset();
       
   705 			}
       
   706 		else
       
   707 			{
       
   708 			// else the PDU is out of place but not actually incorrect so just allow it to drop
       
   709 			aIncomingPdu.Free();
       
   710 			}
       
   711 		}
       
   712 	else
       
   713 		{
       
   714 		// else the PDU is not on our current transaction label so just allow it to drop
       
   715 		aIncomingPdu.Free();
       
   716 		}
       
   717 	}
       
   718 	
       
   719 void CIncomingSduAssembler::ProcessEndPduL(const TAvctpStartHeaderInfo& aHeaderInfo,
       
   720 											RMBufChain& aIncomingPdu)
       
   721 	{
       
   722 	LOG_FUNC
       
   723 
       
   724 	if (iAccretingSdu.Length() &&
       
   725 		iStartHeaderInfo.iTransactionLabel == aHeaderInfo.iTransactionLabel)
       
   726 		{		
       
   727 		// the end packet matches by label - good!
       
   728 		if (iFragmentsReceived == iStartHeaderInfo.iFragmentsInSdu - 1 && // - 1 cause we've not counted this packet yet
       
   729 			iStartHeaderInfo.iMsgType == aHeaderInfo.iMsgType &&		
       
   730 			aIncomingPdu.Length() <= iContinueFragmentSize)
       
   731 
       
   732 			{
       
   733 			iFragmentsReceived++;
       
   734 			aIncomingPdu.TrimStart(EOtherFragHeaderLength);
       
   735 			iAccretingSdu.Append(aIncomingPdu);
       
   736 			
       
   737 			// This is only new'd on the heap so we can safely pass it along.
       
   738 			HAvctpIncomingSdu* completeSdu = new (ELeave) HAvctpIncomingSdu(iMgr.DevAddr(), iAccretingSdu);
       
   739 
       
   740 			iMgr.Protocol().SignalNewDataToSaps(completeSdu, iChannel); // transfers ownership of iAccretingSdu data via the HAvctpIncomingSdu				
       
   741 			Reset(); 
       
   742 			}
       
   743 		else if (aIncomingPdu.Length() > iContinueFragmentSize ||
       
   744 				iStartHeaderInfo.iMsgType != aHeaderInfo.iMsgType)
       
   745 			{
       
   746 			iMgr.Transport().Shutdown(KErrMalformedPacketFromRemote);
       
   747 			Reset();
       
   748 			}
       
   749 		else
       
   750 			{
       
   751 			// else the PDU is out of place but not actually incorrect so just allow it to drop
       
   752 			iAccretingSdu.Free();
       
   753 			}
       
   754 		}
       
   755 	else
       
   756 		{
       
   757 		// else the PDU is not on our current transaction label so just allow it to drop
       
   758 		iAccretingSdu.Free();
       
   759 		}
       
   760 	}