bluetooth/btstack/avctp/avctpmuxerstates.cpp
changeset 0 29b1cd4cb562
child 11 20fda83a6398
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/avctp/avctpmuxerstates.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1193 @@
+// 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:
+// Implement the AVCTP Muxer state classes.
+// These are CAvctpMuxerStateFactory, TAvctpMuxerState (abstract) and its derived
+// classes 
+// Together, these classes and the Muxer implement the State pattern
+// (GOF).  The states themselves are implemented using the Flyweight
+// pattern.  Each state is a Flyweight object, and CAvctpMuxerStateFactory
+// is manager of these objects.  As a result of being a flyweight, no
+// state object may have state that can't be shared between all
+// possible users of the state (i.e. no per-Muxer state)
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+#include <bluetooth/logger.h>
+
+#include <es_prot.h>
+#include <es_mbuf.h>
+
+#include "avctpmuxerstates.h" 
+#include "bt_subconn_levels.h"
+#include "Avctp.h"
+#include "avctpmuxer.h"
+#include "avctputils.h"
+#include "avctpconstants.h"
+#include "avctpPacketMgr.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_AVCTP);
+#endif
+
+using namespace SymbianAvctp;
+
+//
+//                                                                                       //
+// TAvctpMuxerState Implementation                                                       //
+//                                                                                       //
+//
+
+/** 
+Default constructor.
+
+@internalComponent
+@param aFactory The Muxer state factory
+*/
+TAvctpMuxerState::TAvctpMuxerState(CAvctpMuxerStateFactory& aFactory)
+	: iFactory(aFactory)
+	{
+	LOG_FUNC
+	}
+
+/** 
+Change a Muxer from one state to another.
+
+We Exit() the first state and then Enter() the second
+
+@internalComponent
+@param aTransport The Muxer whose state is to be changed
+@param aNewState The index for the new state the Muxer is to transition to
+*/
+void TAvctpMuxerState::ChangeState(CAvctpTransport& aTransport, CAvctpMuxerStateFactory::TAvctpMuxerStates aNewState) const
+	{
+	LOG_FUNC
+
+	aTransport.iState->Exit(aTransport);
+
+#ifdef __FLOG_ACTIVE
+	TAvctpMuxerState& state = iFactory.GetState(aNewState);
+#endif
+	LOG3(_L("Muxer 0x%08x : State %S -> %S"), &aTransport, &(aTransport.iState->iName), &(state.iName));
+	
+	aTransport.iState = &iFactory.GetState(aNewState);
+	aTransport.iState->Enter(aTransport);
+	}
+
+/**
+Calls the appropriate panic function to encode the panic
+code with the current state identifier.
+@param aPanic The panic code that the state is panicking with.
+*/
+void TAvctpMuxerState::PanicInState(SymbianAvctp::TPanic aPanic) const
+	{
+	Panic(aPanic, iFactory.StateIndex(this));
+	}
+	
+/**
+ Close the secondary l2cap channel with or without notifying clients.
+ @param aTransport the transport the state is related to
+ @param aNotifyClient if it's ETrue clients are notified.
+ */
+void TAvctpMuxerState::ShutDownSecondarySap(CAvctpTransport& aTransport, TBool aNotifyClient) const
+	{
+	LOG_FUNC
+	
+	CServProviderBase* sap = aTransport.iChannelSAPs[KAvctpSecondaryChannel];
+	if (sap)
+		{
+		sap->Shutdown(CServProviderBase::EImmediate);
+		delete sap;
+		sap = NULL;
+		aTransport.iChannelSAPs[KAvctpSecondaryChannel] = NULL;
+		if (aNotifyClient)
+			{
+			aTransport.NotifyLinkDown(aTransport.iRemoteAddr, KAvctpSecondaryChannel);
+			}
+		ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+		}
+	}
+
+/**
+Default state entry function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpMuxerState::Enter(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	}
+
+/**
+Default state exit function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpMuxerState::Exit(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC	
+	}
+
+
+/**
+Default Muxer IsIdle
+
+The muxer is asking its state to determine whether it's idle.
+
+@internalComponent
+@param aTransport The Muxer which is idle
+*/
+TBool TAvctpMuxerState::IsIdle(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	TBool hasData = aTransport.HasDataToSend();
+	TBool pidCount = aTransport.ClientCount(); 
+	LOG1(_L("Is Idle: %d"), (!hasData && pidCount == 0));
+	return (!hasData && pidCount == 0);
+	}
+
+/**
+Default Muxer IdleTimerExpired
+
+This is a confirmation that the muxer isn't wanted and so should go
+to the closed state and die.
+
+  @internalComponent
+  @param aTransport The Muxer which is idle
+*/
+void TAvctpMuxerState::IdleTimerExpired(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+	}
+
+/**
+  Default Muxer State Start (outgoing) function.
+
+  We've been asked to start a connection to the specified address
+  The default is to assume that nothing needs to be done.
+  
+  @internalComponent
+  @param aTransport The Muxer which is to start up
+  @param aAddr  The remote address to start up
+  @return System wide error code
+*/
+TInt TAvctpMuxerState::Start(CAvctpTransport& aTransport, const TBTDevAddr& aAddr, TUint16 /*aClientId*/) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aAddr != TBTDevAddr(0) && aTransport.DevAddr() == aAddr, PanicInState(EWrongBTAddress));
+	(void)aAddr;
+	(void)aTransport;
+	return KErrNone;
+	}
+	
+/**
+  Default Muxer State Start (incoming) function.
+
+  We've been asked to start a connection using the given L2CAP sap
+  However, this is only valid when we're in the Closed state so 
+  panic
+  
+  @internalComponent
+  @param aTransport The Muxer which is to start up
+  @param aL2CAPConSAP The existing connection
+  @return System wide error code
+*/
+TInt TAvctpMuxerState::StartIncoming(CAvctpTransport& /*aTransport*/, const TBTDevAddr& /*aAddr*/, CServProviderBase* /*aL2CAPConSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	return KErrNone;
+	}
+
+TInt TAvctpMuxerState::AddSecondChannel(CAvctpTransport& /*aTransport*/, CServProviderBase& /*aSAP*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+
+void TAvctpMuxerState::RemoveSecondChannel(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	}
+
+TInt TAvctpMuxerState::SecondChannelRemoved(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+
+/**
+  Default Muxer State CancelConnectRequest function.
+
+  This is called when a control client wants to cancel a connection to a particular PID.
+  The connection will actually only be cancelled if there are no remaining control
+  clients for this connection.
+        
+  @internalComponent
+  @param aTransport The Muxer which is affected
+*/		
+TInt TAvctpMuxerState::CancelConnectRequest(CAvctpTransport& /*aTransport*/, TUint16 /*aClientId*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady;
+	}
+
+
+/**
+Default Muxer Shutdown function.
+
+  @internalComponent
+  @param aTransport The Muxer which is to shutdown
+*/
+void TAvctpMuxerState::Shutdown(CAvctpTransport& /*aTransport*/, TInt /*aError*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	}
+
+/**
+Default Muxer Disconnect function.
+
+  @internalComponent
+  @param aTransport The Muxer whose L2CAP link has just gone down
+*/
+void TAvctpMuxerState::Disconnect(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	}
+
+/**
+Default Muxer ConnectComplete function.
+
+  @internalComponent
+  @param aTransport The Muxer whose L2CAP connection has just come up
+*/
+void TAvctpMuxerState::ConnectComplete(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	}
+
+/**
+Default Muxer Error function
+
+  @internalComponent
+  @param aTransport The Muxer which has just received an error from it's channel sap
+  @param anError The error
+  @param anOperationMask The effected operation
+*/
+void TAvctpMuxerState::Error(CAvctpTransport& /*aTransport*/, TInt /*aError*/,TUint /*aOperationMask*/, TInt /*aChannel*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	}
+
+/**
+Default Muxer new data function
+
+  @internalComponent
+  @param aTransport The Muxer which has received the notification of new data.
+*/
+TInt TAvctpMuxerState::NewData(CAvctpTransport& /*aTransport*/, TUint /*aMtu*/, TInt /*aChannel*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	return KErrNone;
+	}
+
+/**
+Default Muxer can send function
+
+  @internalComponent
+  @param aTransport The Muxer which can now send
+*/
+void TAvctpMuxerState::CanSend(CAvctpTransport& /*aTransport*/,TInt /*aChannel*/) const
+	{
+	LOG_FUNC
+	PanicInState(EUnexpectedMuxerEvent);
+	}
+
+//
+//                                                                                       //
+// Implementation of TAvctpStateClosed.                                                  //
+//                                                                                       //
+//
+
+/**
+Default constructor
+
+  @internalComponent
+  @param aFactory The Muxer state factory
+*/
+TAvctpStateClosed::TAvctpStateClosed(CAvctpMuxerStateFactory& aFactory)
+	: TAvctpMuxerState(aFactory)
+
+	{
+	LOG_FUNC
+
+	STATENAME("Closed");
+	}
+	
+/**
+Closed state entry function.
+
+This is only called on re-entering the Closed state, so we're not needed so delete ourselves
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateClosed::Enter(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+
+	delete &aTransport;
+	}
+
+/**
+Closed state exit function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateClosed::Exit(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	__ASSERT_ALWAYS(aTransport.DevAddr() != TBTDevAddr(0), PanicInState(ENullTBTDevAddr));
+	}
+
+/**
+Closed Muxer IdleTimerExpired
+
+The idle timer should only expire in a non closed state so panic
+if we get it in this state.
+
+  @internalComponent
+  @param aTransport The Muxer which is idle
+*/
+void TAvctpStateClosed::IdleTimerExpired(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	
+	PanicInState(EUnexpectedMuxerEvent);
+	}
+
+/**
+  Closed Muxer State Start (outgoing) function.
+
+  This function asks us to start a connection to the specified address
+  
+  @internalComponent
+  @param aTransport The Muxer which is to start up
+  @param aAddr  The remote address to start up
+  @return System wide error code
+*/
+TInt TAvctpStateClosed::Start(CAvctpTransport& aTransport, const TBTDevAddr& aAddr, TUint16 /*aClientId*/) const
+	{
+	LOG_FUNC
+
+	__ASSERT_DEBUG(aTransport.DevAddr() == TBTDevAddr(0), PanicInState(ETBTDevAddrNotNull));
+
+	TInt ret = KErrNone;
+	if (aAddr != TBTDevAddr(0))
+		{
+		// New this up just in time.
+		TRAP(ret, aTransport.iChannelSAPs[KAvctpPrimaryChannel] = aTransport.iProtocol.LowerProtocol()->NewSAPL(KSockSeqPacket));
+		if (ret == KErrNone)
+			{
+			aTransport.AssignToDevice(aAddr);			
+			ChangeState(aTransport, CAvctpMuxerStateFactory::ELinkPending);		
+			}
+		}
+	else
+		{
+		// do nothing - stay closed
+		ret = KErrNone;
+		}
+
+	if (ret != KErrNone)
+		{
+		delete &aTransport;
+		}
+	return ret;
+	}
+	
+/**
+  Closed Muxer State Start (incoming) function.
+
+  We've been asked to start a connection using the given L2CAP sap
+  
+  @internalComponent
+  @param aTransport The Muxer which is to start up
+  @param aL2CAPConSAP The existing connection
+  @return System wide error code
+*/
+TInt TAvctpStateClosed::StartIncoming(CAvctpTransport& aTransport, const TBTDevAddr& aAddr, CServProviderBase* aL2CAPConSAP) const
+	{
+	LOG_FUNC
+
+	TInt ret = SymbianAvctp::KErrBadAddress;
+	
+	// If the following is not true we'll Kern-Exec 3 anyway so assert always
+	__ASSERT_ALWAYS(aL2CAPConSAP, PanicInState(ENullLowerProtocolSap));
+	__ASSERT_DEBUG(aTransport.DevAddr() == TBTDevAddr(0), PanicInState(ETBTDevAddrNotNull));
+
+	if (aAddr != TBTDevAddr(0))
+		{
+		aTransport.AssignToDevice(aAddr);		
+		aTransport.iChannelSAPs[KAvctpPrimaryChannel] = aL2CAPConSAP;
+		aTransport.iChannelSAPs[KAvctpPrimaryChannel]->SetNotify(&aTransport);
+		
+		aTransport.iChannelSAPs[KAvctpPrimaryChannel]->Start();
+		ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);		
+		ret = KErrNone;
+		}
+	// else covered by ret
+
+	if (ret != KErrNone)
+		{
+		delete &aTransport;
+		}
+	return ret;
+	}
+	
+//
+//                                                                                       //
+// Implementation of void TAvctpStateLinkPending                                         //
+//                                                                                       //
+// Represents a muxer waiting for the L2CAP link to be created.                          //
+//                                                                                       //
+//
+
+/**
+Default constructor
+
+  @internalComponent
+  @param aFactory The Muxer state factory
+*/
+TAvctpStateLinkPending::TAvctpStateLinkPending(CAvctpMuxerStateFactory& aFactory)
+	: TAvctpMuxerState(aFactory)
+
+	{
+	LOG_FUNC
+	STATENAME("LinkPending");
+	}
+
+/**
+Link Pending state entry function.
+
+We request the lower protocol SAP to bring up the link.
+
+@internalComponent
+@param aTransport The Muxer which is waiting for a link
+*/
+void TAvctpStateLinkPending::Enter(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+
+	__ASSERT_ALWAYS(aTransport.iChannelSAPs[KAvctpPrimaryChannel], PanicInState(ENullLowerProtocolSap));
+	
+	aTransport.DequeIdleTimer();
+	// we become the socket for iChannelsSAPs[0]
+	aTransport.iChannelSAPs[KAvctpPrimaryChannel]->SetNotify(&aTransport);
+	
+	TL2CAPSockAddr addr;
+	addr.SetBTAddr(aTransport.DevAddr());
+	addr.SetPort(KAVCTP);
+
+	// the security settings are:	
+	// (though see :Preauthorise() for the authentication exceptions due to avdtp authentication)
+	TBTServiceSecurity sec;
+	sec.SetAuthentication(KOutboundAuthenticationDefault);
+	sec.SetAuthorisation(KOutboundAuthoristationDefault);
+	sec.SetEncryption(KOutboundEncryptionDefault);
+	sec.SetDenied(EFalse);
+	sec.SetUid(KAvctpServiceUid);	
+	addr.SetSecurity(sec);
+	
+	TInt err = aTransport.iChannelSAPs[KAvctpPrimaryChannel]->SetRemName(addr);
+	__ASSERT_DEBUG(!err, PanicInState(EErrorSettingAddress));
+	
+	// Bring up the L2CAP link
+	aTransport.iChannelSAPs[KAvctpPrimaryChannel]->ActiveOpen();	
+	}
+
+// TAvctpStateLinkPending::Exit - we'd lke to call aTransport.CheckForIdle(0) but cause
+// in this state IsIdle always returns EFalse that's not possible. Hence do the
+// CheckForIdle in the Enter of the next state currently Open or Closed.
+
+
+
+
+/**
+Link Pending Muxer IsIdle
+
+The muxer is asking it's state to determine whether it's idle. Cause the link is pending
+we can't be idle whatever happens. 
+
+Note that this means we must call CheckForIdle on aTransport on entering the next state.
+
+  @internalComponent
+  @param aTransport The Muxer which is idle
+*/
+TBool TAvctpStateLinkPending::IsIdle(CAvctpTransport& /*aTransport*/) const
+	{
+	LOG_FUNC
+	return EFalse;
+	}
+	
+/**
+  Link Pending Muxer State CancelConnnectRequest function.
+
+  This is called when a control client wants to cancel a connection to a particular PID.
+  The connection will actually only be cancelled if there are no remaining control
+  clients for this connection.
+  
+  This function just removes the saplinksmgr on aPid from the list of control
+  clients since it no longer is interested in this remote device and shouldn't 
+  receive any more events related to it.
+    
+  @internalComponent
+  @param aTransport The Muxer which is affected
+  @param aPid The pid to cancel the connection too
+*/		
+TInt TAvctpStateLinkPending::CancelConnectRequest(CAvctpTransport& /*aTransport*/, TUint16 /*aClientId*/) const
+	{
+	LOG_FUNC
+	return KErrNotSupported;
+	}
+
+
+/**
+Link Pending Muxer ConnectComplete function.
+
+This is the successful result of a connection attempt to a remote device. 
+(A incoming connection wouldn't have resulted in a BearerConnectComplete on the
+protocol instead)
+
+  @internalComponent
+  @param aTransport The Muxer whose L2CAP connection has just come up
+*/
+void TAvctpStateLinkPending::ConnectComplete(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+	aTransport.NotifyLinkUp(aTransport.iRemoteAddr);
+	}
+
+/**
+Link Pending Muxer Error function
+
+This is called after some kind of error in the lower protocol Sap.
+
+  @internalComponent
+  @param aTransport The Muxer which has just received an error from it's iChannelsSAPs[0]
+  @param anError The error
+  @param anOperationMask The effected operation
+*/
+void TAvctpStateLinkPending::Error(CAvctpTransport& aTransport, TInt aError,TUint aOperationMask, TInt aChannel) const
+	{
+	LOG_FUNC
+
+	__ASSERT_DEBUG(aChannel == KAvctpPrimaryChannel, PanicInState(EAvctpInvalidChannel));
+	
+	if (aOperationMask & (MSocketNotify::EErrorFatal   | 
+	  				      MSocketNotify::EErrorConnect | 
+	  				      MSocketNotify::EErrorClose   | 
+					 	  MSocketNotify::EErrorAllOperations))
+		{
+		// The connect failed, so we'd better go to the Closed state
+		// and tell clients what's happened.
+		// Notifications are made before changing the state because the Enter() method of the Close state
+		// delete the transport, so we can't call anything after changing the state.
+
+		aTransport.NotifyLinkError(aError, aChannel == KAvctpSecondaryChannel);
+		ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+		}
+	else if (aOperationMask & (MSocketNotify::EErrorSend  | 
+	  	 	 		       	   MSocketNotify::EErrorRecv  |
+	  	 	 		       	   MSocketNotify::EErrorIoctl))
+		{
+		// Since the connection isn't up, we shouldn't be getting a send or recv error
+		// nor do we currently support ioctls in the muxer so:
+		PanicInState(EUnexpectedMuxerEvent);
+		}		
+	}
+
+//
+//                                                                                       //
+// Implementation of state TAvctpStateOpen                                               //
+//                                                                                       //
+// This represents a fully connected Muxer that can send and receive data                //
+//                                                                                       //
+//
+
+/**
+Default constructor
+
+  @internalComponent
+  @param aFactory The Muxer state factory
+*/
+TAvctpStateOpen::TAvctpStateOpen(CAvctpMuxerStateFactory& aFactory)
+	: TAvctpMuxerState(aFactory)
+
+	{
+	LOG_FUNC
+	STATENAME("Open");
+	}
+	
+/**
+Open state entry function.
+
+In case a Avctp Sap asked to send data we need to signal them that they can now send
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateOpen::Enter(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	
+	aTransport.SetClearToSend(KAvctpPrimaryChannel);	//only first channel is open so far
+	aTransport.PacketMgr().CanSend(KAvctpPrimaryChannel);
+	
+	// for stereo headset usecase, pre-authorise device for AVDTP 
+	aTransport.iProtocol.SetPreauthorisation(aTransport.iRemoteAddr, ETrue);
+	}
+
+/**
+Open state exit function.
+
+@internalComponent
+@param aTransport The Muxer whose state is changing
+*/
+void TAvctpStateOpen::Exit(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+
+	// for stereo headset usecase, de-pre-authorise device for AVDTP 
+	aTransport.iProtocol.SetPreauthorisation(aTransport.iRemoteAddr, EFalse);
+	}
+
+
+/**
+  Open Muxer State Start (outgoing) function.
+
+  We've been asked to start a connection to the specified address
+  The connection is already up so immediately send a ConnectCfm event
+  
+  @internalComponent
+  @param aTransport The Muxer which is to start up
+  @param aAddr  The remote address to start up
+  @return System wide error code
+*/
+TInt TAvctpStateOpen::Start(CAvctpTransport& aTransport, const TBTDevAddr& __DEBUG_ONLY(aAddr), TUint16 aClientId) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aAddr != TBTDevAddr(0) && aTransport.DevAddr() == aAddr, PanicInState(EWrongBTAddress));
+ 
+	aTransport.NotifyAttachConfirm(aClientId, KErrNone, EFalse);
+	return KErrNone;
+	}
+	
+	
+/**
+Open Muxer Shutdown function.
+
+This function allows the muxer to be shutdown irrespective of whether 
+it is idle. This is intended to be used to punish a remote device that
+has done something naughty.
+
+Notify all clients of the problem and go to the closed state.
+
+  @internalComponent
+  @param aTransport The Muxer which is sending data
+*/
+void TAvctpStateOpen::Shutdown(CAvctpTransport& aTransport, TInt /*aError*/) const
+	{
+	LOG_FUNC
+
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+	}
+
+
+/**
+Open Muxer Disconnect function.
+
+This is the result of a remote device disconnecting from us.
+Let all interested parties know.
+
+  @internalComponent
+  @param aTransport The Muxer whose L2CAP link has just gone down
+*/
+void TAvctpStateOpen::Disconnect(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+
+	aTransport.iProtocol.PrimaryChannelIncomingRemoteDisconnection(aTransport.iRemoteAddr); 
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);		
+	}
+
+/**
+Open Muxer Error function
+
+This is called after some kind of error in the lower protocol Sap.
+
+  @internalComponent
+  @param aTransport The Muxer which has just received an error from it's channel sap
+  @param anError The error
+  @param anOperationMask The affected operation
+*/	
+void TAvctpStateOpen::Error(CAvctpTransport& aTransport, TInt aError,TUint aOperationMask, TInt aChannel) const
+	{	
+	LOG_FUNC
+
+	__ASSERT_DEBUG(aChannel == KAvctpPrimaryChannel, PanicInState(EAvctpInvalidChannel));
+	
+	if (aOperationMask & (MSocketNotify::EErrorRecv |
+						  MSocketNotify::EErrorSend))
+		{
+		// the packet mgr is only interested in data plane errors
+		aTransport.PacketMgr().SignalMuxerError(aError, aOperationMask);
+		}	
+
+	if (aOperationMask & (MSocketNotify::EErrorFatal   | 
+	  				      MSocketNotify::EErrorClose   | 
+					 	  MSocketNotify::EErrorAllOperations))
+		{
+		// The connection has gone down so we inform our control clients of this fact	
+		aTransport.NotifyLinkDown(aTransport.iAddress, aChannel, aError);
+		}
+	else if (aOperationMask & (MSocketNotify::EErrorConnect |
+							   MSocketNotify::EErrorIoctl))
+		{
+		// Since the connection is already up, we shouldn't be getting a connect error
+		// nor do we currently support ioctls
+		PanicInState(EUnexpectedMuxerEvent);
+		}
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+	}
+
+TInt TAvctpStateOpen::AddSecondChannel(CAvctpTransport& aTransport, CServProviderBase& aSAP) const
+	{
+	LOG_FUNC
+	// can bind socket to SAP now
+	aTransport.BindSecondaryChannelSap(aSAP);
+	
+	// see if it is connected or not
+	TL2CAPSockAddr addr;
+	aSAP.RemName(addr);
+	
+	if (addr.BTAddr()==TBTDevAddr(0))
+		{
+		addr.SetBTAddr(aTransport.iRemoteAddr);
+		addr.SetPort(KAvctpSecondChannelPSM);
+
+		// the security settings are:	
+		// (though see :Preauthorise() for the authentication exceptions due to avdtp authentication)
+		TBTServiceSecurity sec;
+		sec.SetAuthentication(KSecondaryChannelAuthenticationDefault);
+		sec.SetAuthorisation(KSecondaryChannelAuthoristationDefault);
+		sec.SetEncryption(KOutboundEncryptionDefault);
+		sec.SetDenied(EFalse);
+		sec.SetUid(KAvctpServiceUid);	
+		addr.SetSecurity(sec);
+		
+		TInt err = aTransport.iChannelSAPs[KAvctpSecondaryChannel]->SetRemName(addr);
+		__ASSERT_DEBUG(err == KErrNone, PanicInState(ESetRemNameError));
+
+		const TUint KDefaultMtu = 335;
+		
+		TPckgBuf<TL2CapConfig> config;
+		config().SetMaxTransmitUnitSize(KAvctpSecondaryChannelInboundMTU);
+		config().SetMinMTU(KDefaultMtu);
+		config().SetMaxReceiveUnitSize(KAvctpSecondaryChannelInboundMTU);
+		config().SetMinMRU(KDefaultMtu);
+
+		err = aTransport.iChannelSAPs[KAvctpSecondaryChannel]->SetOption(KSolBtL2CAP, KL2CAPUpdateChannelConfig, config); 
+		__ASSERT_DEBUG(err == KErrNone, Panic(ESetOptionError));
+
+		aTransport.iChannelSAPs[KAvctpSecondaryChannel]->ActiveOpen();
+		ChangeState(aTransport, CAvctpMuxerStateFactory::ESecondLinkPending);
+		}
+	else
+		{
+		aTransport.iChannelSAPs[KAvctpSecondaryChannel]->Start();
+		aTransport.SetClearToSend(KAvctpSecondaryChannel);
+		ChangeState(aTransport, CAvctpMuxerStateFactory::EFullyOpen);
+		aTransport.NotifyLinkUp(addr.BTAddr(), ETrue);
+		}
+	return KErrNone;
+	}
+
+/**
+Open Muxer new data function
+
+The lower protocol sap has notified the muxer of new data that is 
+waiting for retrieval.
+
+This is called once for each new packet of data that L2CAP has notified the muxer of.
+We get to the data by calling GetData on the lower protocol SAP 
+and give the resulting data to the Avctp Protocol, letting it workout who wants it.
+
+This assumes a packet interface from L2CAP.
+
+  @internalComponent
+  @param aTransport The Muxer which has received the notification of new data.
+  @param aMtu The length of the data packet to be read. 
+*/
+TInt TAvctpStateOpen::NewData(CAvctpTransport& aTransport, TUint aMtu, TInt aChannel) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aChannel==KAvctpPrimaryChannel, PanicInState(EUnexpectedMuxerEvent));
+	__ASSERT_DEBUG(aTransport.iChannelSAPs[aChannel], PanicInState(ENullLowerProtocolSap));
+	
+	TInt err = KErrNone;
+	// Read data into the buffer
+	// the transport feeds us synchronously for first channel
+	RMBufChain inboundFragment;
+	TInt dataAvailable = aTransport.iChannelSAPs[KAvctpPrimaryChannel]->GetData(inboundFragment, aMtu, 0);
+	if (dataAvailable > 0)
+		{
+		err = aTransport.iPacketMgr->NewData(inboundFragment, aChannel); // ownership xferred;
+		
+		//NewData() only returns an error in the case where the data header gave a parse error.
+		//In this case the muxer is shutdown, so the remaining packets cannot be read.
+		//In the case where NewData() failed to pass on onwnership, an attempt should be made
+		//to read remaining packets, so no error is returned.
+		if(err != KErrNone)
+			{
+			inboundFragment.Free();
+			}
+		}
+	else if (dataAvailable < KErrNone)	// some error occurred reading the data. shutdown the muxer and report the error
+		{
+		aTransport.Shutdown(dataAvailable);
+		inboundFragment.Free();
+		err = KErrMuxerShutDown;
+		}
+	// otherwise, no data available
+	return err;
+	}
+		
+/**
+Open Muxer can send function
+
+This is called after a blocked Write on the lower protocol SAP. This is a notification
+that the lower protocol SAP is ready to receive more data.
+
+  @internalComponent
+  @param aTransport The Muxer which can now send
+*/
+void TAvctpStateOpen::CanSend(CAvctpTransport& aTransport, TInt aChannel) const
+	{
+	LOG_FUNC
+
+	aTransport.SetClearToSend(aChannel);	
+	aTransport.PacketMgr().CanSend(aChannel);
+	}
+
+TAvctpStateFullyOpen::TAvctpStateFullyOpen(CAvctpMuxerStateFactory& aFactory)
+:TAvctpStateOpen(aFactory)
+	{
+	LOG_FUNC
+	STATENAME("FullyOpen");
+	}
+
+void TAvctpStateFullyOpen::Enter(CAvctpTransport& aTransport) const
+	{
+	// should check the sap psm really
+	aTransport.SetClearToSend(KAvctpSecondaryChannel);
+	aTransport.PacketMgr().CanSend(KAvctpSecondaryChannel);
+	}
+
+/**
+ The method is defined and left empty on purpose (because this class derives from TAvctpStateOpen 
+ but we don't wont its method to be called.
+ */
+void TAvctpStateFullyOpen::Exit(CAvctpTransport& /*aTransport*/) const
+	{
+	}
+
+void TAvctpStateFullyOpen::Error(CAvctpTransport& aTransport, TInt aError, TUint aErrorMask, TInt aChannel) const
+	{
+	LOG_FUNC
+
+    if (aErrorMask & (MSocketNotify::EErrorRecv |
+                          MSocketNotify::EErrorSend))
+        {
+        // the packet mgr is only interested in data plane errors
+        aTransport.PacketMgr().SignalMuxerError(aError, aErrorMask);
+        }   
+
+    if (aErrorMask & (MSocketNotify::EErrorFatal   | 
+                          MSocketNotify::EErrorClose   | 
+                          MSocketNotify::EErrorAllOperations))
+        {
+        // The connection has gone down so we inform our control clients of this fact   
+        aTransport.NotifyLinkDown(aTransport.iAddress, aChannel, aError);
+        }
+    else if (aErrorMask & (MSocketNotify::EErrorConnect |
+                               MSocketNotify::EErrorIoctl))
+        {
+        // Since the connection is already up, we shouldn't be getting a connect error
+        // nor do we currently support ioctls
+        PanicInState(EUnexpectedMuxerEvent);
+        }
+    ChangeState(aTransport, aChannel == KAvctpSecondaryChannel ? CAvctpMuxerStateFactory::EOpen : CAvctpMuxerStateFactory::EClosed);
+	}
+
+void TAvctpStateFullyOpen::Disconnect(CAvctpTransport& aTransport) const
+	{
+	aTransport.iProtocol.PrimaryChannelIncomingRemoteDisconnection(aTransport.iRemoteAddr); 
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);		
+	}
+
+void TAvctpStateFullyOpen::CanSend(CAvctpTransport& aTransport,TInt aChannel) const
+	{
+	aTransport.SetClearToSend(aChannel);	
+	aTransport.PacketMgr().CanSend(aChannel);
+	}
+
+TInt TAvctpStateFullyOpen::NewData(CAvctpTransport& aTransport, TUint aMtu, TInt aChannel) const
+	{
+	RMBufChain inboundFragment;
+	__ASSERT_DEBUG(aTransport.iChannelSAPs[aChannel], PanicInState(ENullLowerProtocolSap));
+	aTransport.iChannelSAPs[aChannel]->GetData(inboundFragment, aMtu, 0);
+	
+	TInt err = aTransport.iPacketMgr->NewData(inboundFragment, aChannel); // ownership xferred;
+	
+	if(err != KErrNone)
+		{
+		inboundFragment.Free();
+		}
+	return err;
+	}
+
+TInt TAvctpStateFullyOpen::Start(CAvctpTransport& aTransport, const TBTDevAddr& /*aAddr*/, TUint16 aClientId) const
+	{
+	aTransport.NotifyAttachConfirm(aClientId, KErrNone, EFalse);
+	return KErrNone;
+	}
+
+void TAvctpStateFullyOpen::RemoveSecondChannel(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	// shutdown secondary channel without notifying clients (second param is EFalse)
+	ShutDownSecondarySap(aTransport, EFalse);
+	}
+
+TInt TAvctpStateFullyOpen::SecondChannelRemoved(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	// shutdown secondary channel notifying clients (second param is ETrue)
+	ShutDownSecondarySap(aTransport, ETrue);
+	return KErrNone;
+	}
+
+void TAvctpStateFullyOpen::Shutdown(CAvctpTransport& aTransport, TInt /*aError*/) const
+	{
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+	}
+
+
+/**
+ The method is declared and left empty on purpose (because this class derives from TAvctpStateOpen 
+ but we don't wont its method to be called.
+ */
+void TAvctpStateSecondChannelPending::Enter(CAvctpTransport& /*aTransport*/) const
+	{
+	}
+
+/**
+ The method is declared and left empty on purpose (because this class derives from TAvctpStateOpen 
+ but we don't wont its method to be called.
+ */
+void TAvctpStateSecondChannelPending::Exit(CAvctpTransport& /*aTransport*/) const
+	{
+	}
+
+void TAvctpStateSecondChannelPending::Error(CAvctpTransport& aTransport, TInt aError, TUint /*aErrorMask*/, TInt aChannel) const
+	{
+	aTransport.NotifyLinkError(aError, aChannel == KAvctpSecondaryChannel);
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EOpen);
+	}
+
+TAvctpStateSecondChannelPending::TAvctpStateSecondChannelPending(CAvctpMuxerStateFactory& aFactory)
+:TAvctpStateOpen(aFactory)
+	{
+	LOG_FUNC
+	STATENAME("SecondLinkPending");
+	}
+
+void TAvctpStateSecondChannelPending::ConnectComplete(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	aTransport.NotifyLinkUp(aTransport.iRemoteAddr, ETrue);
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EFullyOpen);
+	}
+
+void TAvctpStateSecondChannelPending::Disconnect(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	
+	// In this state there is at least one outstanding ioctl on the secondary ctrl sap that 
+	// we must complete
+	
+	aTransport.NotifyAttachConfirm(KErrMuxerShutDown, ETrue);
+	aTransport.iProtocol.PrimaryChannelIncomingRemoteDisconnection(aTransport.iRemoteAddr); 
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);		
+	}
+
+void TAvctpStateSecondChannelPending::CanSend(CAvctpTransport& aTransport, TInt __DEBUG_ONLY(aChannel)) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aChannel == KAvctpPrimaryChannel, PanicInState(EAvctpInvalidChannel));
+	aTransport.SetClearToSend(KAvctpPrimaryChannel);	
+	aTransport.PacketMgr().CanSend(KAvctpPrimaryChannel);
+	}
+
+TInt TAvctpStateSecondChannelPending::NewData(CAvctpTransport& aTransport, TUint aMtu, TInt aChannel) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aChannel==KAvctpPrimaryChannel, PanicInState(EUnexpectedMuxerEvent));
+	__ASSERT_DEBUG(aTransport.iChannelSAPs[aChannel], PanicInState(ENullLowerProtocolSap));
+	
+	// Read data into the buffer
+	// the transport feeds us synchronously for first channel
+	RMBufChain inboundFragment;
+	aTransport.iChannelSAPs[KAvctpPrimaryChannel]->GetData(inboundFragment, aMtu, 0);
+
+	TInt err = aTransport.iPacketMgr->NewData(inboundFragment, aChannel); // ownership xferred;
+	
+	//NewData() only returns an error in the case where the data header gave a parse error.
+	//In this case the muxer is shutdown, so the remaining packets cannot be read.
+	//In the case where NewData() failed to pass on onwnership, an attempt should be made
+	//to read remaining packets, so no error is returned.
+	if(err != KErrNone)
+		{
+		inboundFragment.Free();
+		}
+	return err;
+	}
+
+TInt TAvctpStateSecondChannelPending::Start(CAvctpTransport& /*aTransport*/, const TBTDevAddr& /*aAddr*/, TUint16 /*aClientId*/) const
+	{
+	return KErrNotReady;
+	}
+
+void TAvctpStateSecondChannelPending::Shutdown(CAvctpTransport& aTransport, TInt /*aError*/) const
+	{
+	LOG_FUNC
+	ChangeState(aTransport, CAvctpMuxerStateFactory::EClosed);
+	}
+
+void TAvctpStateSecondChannelPending::RemoveSecondChannel(CAvctpTransport& aTransport) const
+	{
+	LOG_FUNC
+	// shutdown secondary channel without notifying clients (second param is EFalse)
+	ShutDownSecondarySap(aTransport, EFalse);
+	}
+//
+//                                                                                       //
+// CAvctpMuxerStateFactory implementation                                                     //
+//                                                                                       //
+//
+
+/**
+Default constructor
+
+  @internalComponent
+*/
+CAvctpMuxerStateFactory::CAvctpMuxerStateFactory()
+	{
+	LOG_FUNC
+	}
+
+/**
+Destructor to free resources.
+
+Delete all our lightweight states
+
+  @internalComponent
+*/
+CAvctpMuxerStateFactory::~CAvctpMuxerStateFactory()
+	{
+	LOG_FUNC
+
+	iStates.DeleteAll();
+	}
+
+/**
+Static factory factory function (think about it... ;-)
+
+Creates an array of lightweight states for Muxers
+
+  @internalComponent
+  @leave KErrNoMemory if the CAvctpMuxerStateFactory object could not be created
+  @return A pointer to the new state factory
+*/
+CAvctpMuxerStateFactory* CAvctpMuxerStateFactory::NewL()
+	{
+	LOG_STATIC_FUNC
+
+	CAvctpMuxerStateFactory* factory = new(ELeave) CAvctpMuxerStateFactory();
+	CleanupStack::PushL(factory);
+
+	// Create all the new states
+	factory->iStates[EClosed]	  	 = new(ELeave) TAvctpStateClosed(*factory);
+	factory->iStates[ELinkPending]	 = new(ELeave) TAvctpStateLinkPending(*factory);
+	factory->iStates[EOpen]		  	 = new(ELeave) TAvctpStateOpen(*factory);
+	factory->iStates[ESecondLinkPending] = new(ELeave) TAvctpStateSecondChannelPending(*factory);
+	factory->iStates[EFullyOpen] = new(ELeave) TAvctpStateFullyOpen(*factory);
+	
+	CleanupStack::Pop(factory);
+	return factory;
+	}
+
+/**
+Utility function to get a lightweight state
+
+  @internalComponent
+  @param aState Index to the state required
+  @return A lightweight Muxer state
+*/
+TAvctpMuxerState& CAvctpMuxerStateFactory::GetState(const TAvctpMuxerStates aState) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aState != EMaxStates, Panic(EAvctpMuxerStateOutOfBounds));
+	return *iStates[aState];
+	}
+
+TInt CAvctpMuxerStateFactory::StateIndex(const TAvctpMuxerState* aState) const
+	{
+	TInt state;
+	for (state = 0; state < EMaxStates; state++)
+		{
+		if (iStates[state] == aState)
+			{
+			return state;
+			}
+		}
+	
+	return KUnknownState;
+	}