bluetooth/btstack/l2cap/l2sapstates.cpp
changeset 0 29b1cd4cb562
child 8 2b6718f05bdb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btstack/l2cap/l2sapstates.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,1560 @@
+// Copyright (c) 1999-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 L2CAP sap state classes.
+// These are CL2CAPSAPStateFactory, TL2CAPSAPState (abstract) and its derived
+// classes
+// Together, these classes and the SAP implement the State pattern
+// (GOF).  The states themselves are implemented using the Flyweight
+// pattern.  Each state is a Flyweight object, and CL2CAPSAPStateFactory
+// 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 (ie no per-SAP state)
+// 
+//
+
+#include <bluetooth/logger.h>
+
+#include <bt_sock.h>
+
+#include "l2sapstates.h"
+
+#include "L2CapSDUQueue.h"
+#include "L2CapDataController.h"
+#include "l2capSAPSignalHandler.h"
+
+#include "l2sap.h"
+#include "l2cap.h"
+
+#include "l2util.h"
+
+#ifdef _DEBUG
+#include "L2CapDebugControlInterface.h"
+#endif
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_L2CAP);
+#endif
+
+/*************************************************************************/
+//
+// TL2CAPSAPState Implementation
+//
+
+TL2CAPSAPState::TL2CAPSAPState(CL2CAPSAPStateFactory& aFactory)
+: iFactory(aFactory)
+	{
+	LOG_FUNC
+	}
+
+void TL2CAPSAPState::PanicInState(TL2CAPPanic aPanic) const
+	{
+	LOG_FUNC
+	Panic(aPanic, iFactory.StateIndex(this));
+	}
+
+#ifdef _DEBUG
+void TL2CAPSAPState::DebugPanicInState(TL2CAPPanic aPanic) const
+#else
+void TL2CAPSAPState::DebugPanicInState(TL2CAPPanic /*aPanic*/) const
+#endif
+	{
+	LOG_FUNC
+	#ifdef _DEBUG
+	PanicInState(aPanic);
+	#endif
+	}
+
+void TL2CAPSAPState::StartCalledWhileDisconnected(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// This function is intended to be called (under some circumstances when a Start()
+	// has been received. This handles the case where in between the Start() call and
+	// the construction of the cloned SAP on which the Start is being made, the link
+	// which prompted the cloning has disconnected.  Therefore, if we are a cloned sap
+	// and have been "coupled" with an client side socket we need to inform it of the
+	// disconnection.
+	if(aSAP.ListeningSAP())
+		{
+		if(aSAP.Socket())
+			{
+			if(aSAP.SocketErrorCode() == KErrNone)
+				{
+				aSAP.Socket()->Disconnect();
+				}
+			else
+				{
+				aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+				}
+			}
+		// We also need to take ourselves off the listening SAP's 'clone' queue, just 
+		// as we do in the fair weather case when Start is called in state 'Accepting'.
+		aSAP.DetachFromListeningSAP();
+		}
+	}
+
+// DEFAULT Implementations
+// Socket Initiated.
+void TL2CAPSAPState::Start(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+
+TInt TL2CAPSAPState::Ioctl(CL2CAPConnectionSAP& /*aSAP*/, TUint /*aLevel*/, TUint /*aName*/, TDes8* /*aOption*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	return KErrSAPUnexpectedEvent;
+	}
+
+
+void TL2CAPSAPState::CancelIoctl(CL2CAPConnectionSAP& /*aSAP*/, TUint /*aLevel*/, TUint /*aName*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+
+void TL2CAPSAPState::IoctlComplete(CL2CAPConnectionSAP& /*aSAP*/, TInt /*aErr*/, TUint /*aLevel*/, TUint /*aName*/, TDesC8* /*aBuf*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+	
+void TL2CAPSAPState::ActiveOpen(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+
+TInt TL2CAPSAPState::PassiveOpen(CL2CAPConnectionSAP& /*aSAP*/, TUint /*aQueSize*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	return KErrSAPUnexpectedEvent;
+	}
+
+void TL2CAPSAPState::Shutdown(CL2CAPConnectionSAP& /* aSAP */) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+
+void TL2CAPSAPState::FastShutdown(CL2CAPConnectionSAP& /* aSAP */) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+
+TInt TL2CAPSAPState::Send(CL2CAPConnectionSAP& /*aSAP*/, RMBufChain& /*aData*/, TUint /*aFlag*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	return KErrNotReady; // Indicate that no data has been sent.
+	}
+
+TInt TL2CAPSAPState::Read(CL2CAPConnectionSAP& /*aSAP*/, RMBufChain& /*aData*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	return KErrNotReady;
+	}
+	
+void TL2CAPSAPState::Bound(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSocketEvent);
+	}
+	
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPState::ChannelConfigured(CL2CAPConnectionSAP& /*aSAP*/,
+	                                   CL2CapChannelConfig& /*aConfig*/,
+                                       CL2CAPMux& /*aMuxer*/,
+                                       TL2CAPPort /*aLocalPort*/,
+                                       TL2CAPPort /*aRemotePort*/)
+	{
+	LOG_FUNC
+	DebugPanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}
+
+void TL2CAPSAPState::ReconfiguringChannel(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	DebugPanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}
+
+void TL2CAPSAPState::ChannelClosed(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}
+
+void TL2CAPSAPState::CloseOutgoingSDUQueue(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}	
+
+void TL2CAPSAPState::SignalHandlerError(CL2CAPConnectionSAP& /*aSAP*/, TInt /*aErrorCode*/, MSocketNotify::TOperationBitmasks /*aErrorAction*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}	
+
+void TL2CAPSAPState::LinkUp(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}	
+
+void TL2CAPSAPState::ChannelOpened(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSAPSignalHandlerEvent);
+	}	
+
+// Events called from the Data Controller.
+void TL2CAPSAPState::NewData(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	}
+
+TInt TL2CAPSAPState::NewDataAsyncCallBack(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	//Need to return something to stop error in compiler
+	return(KErrNone);
+	}
+
+void TL2CAPSAPState::CanSend(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	}
+
+void TL2CAPSAPState::SDUQueueClosed(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	}
+
+void TL2CAPSAPState::DataPlaneError(CL2CAPConnectionSAP& /*aSAP*/, TInt /*aErrorCode*/, MSocketNotify::TOperationBitmasks /*aErrorAction*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	}
+
+// Events from the security manager.
+void TL2CAPSAPState::AccessRequestComplete(CL2CAPConnectionSAP& /*aSignalHandler*/, TInt /*aResult*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedSecurityManagerEvent);
+	}
+
+
+// State Transition Actions.
+void TL2CAPSAPState::Enter(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	}
+	
+void TL2CAPSAPState::Exit(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	}
+	
+// Helper method.
+void TL2CAPSAPState::NotifySocketClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Enter the closed state.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	
+	// Check if this is owned by the socket yet.  If it is the socket needs
+	// to be notified, and is responsible for deleting this SAP.
+	if(aSAP.Socket())
+		{
+		switch(aSAP.ShutdownReceived())
+			{
+			case CL2CAPConnectionSAP::ESAPShutdownNormal:
+				aSAP.Socket()->CanClose();
+				break;
+
+			case CL2CAPConnectionSAP::ESAPShutdownNone:
+				if(aSAP.SocketErrorCode() == KErrNone)
+					{
+					aSAP.Socket()->Disconnect();
+					}
+				else
+					{
+					// An error has occurred, enter the error state.
+					aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EError));
+					aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+					}
+				break;
+
+			case CL2CAPConnectionSAP::ESAPShutdownImmediate:
+				break;
+				
+			default:
+				PanicInState(EL2CAPInvalidSAPShutdownType);
+				break;	
+			};
+		}
+	else
+		{
+		if(!aSAP.IsAcceptPending())
+			{
+			// This is not owned by a socket - delete it.
+			aSAP.DetachFromListeningSAP();
+			aSAP.DeleteSAP();
+			}
+		}
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateClosed Implementation
+//
+TL2CAPSAPStateClosed::TL2CAPSAPStateClosed(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+// Events called from the SAP.
+void TL2CAPSAPStateClosed::Start(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// If a passive connection was established and then disconnected by the peer
+	// the Start notification will be received in this state.
+	// This is handled in the Closed state rather than in the Bound state since
+	// we're not bound from the stack's point of view in this situation.
+	StartCalledWhileDisconnected(aSAP);
+	}
+
+void TL2CAPSAPStateClosed::ActiveOpen(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EActiveLinkPending));
+
+	// If there is a Service set for CodMan, register it.
+	aSAP.RegisterCodService();
+
+	TInt rerr = aSAP.Protocol().MuxController().AttachActiveSignalHandler(aSAP.SignalHandler(), aSAP.RemoteDev());
+	if(rerr != KErrNone)
+		{
+		// Set up an error condition to indicate that the connection
+		// has failed.
+		aSAP.SetSocketErrorCode(KErrCouldNotConnect);
+		aSAP.SetSocketErrorAction(MSocketNotify::EErrorConnect);
+		
+		NotifySocketClosed(aSAP);	
+		}
+	}
+	
+void TL2CAPSAPStateClosed::SDUQueueClosed(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// Nothing needs to be done here.  FastShutdown scenario.
+	}
+	
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateClosed::ChannelClosed(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// Ignore in this state.  This will be due to a fast shutdown.
+	}
+
+void TL2CAPSAPStateClosed::SignalHandlerError(CL2CAPConnectionSAP& /*aSAP*/, TInt /*aErrorCode*/, MSocketNotify::TOperationBitmasks /*aErrorAction*/) const
+	{
+	LOG_FUNC
+	// Ignore in this state.  This will be due to a fast shutdown.
+	}	
+
+void TL2CAPSAPStateClosed::Enter(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.iNewDataToNotify = 0;	
+	aSAP.DeregisterCodService();	// See if there is a Service to remove for CodMan
+	}
+
+void TL2CAPSAPStateClosed::FastShutdown(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// Shutdown is permitted by ESOCK on an open (not connected) socket.
+	// Therefore this must be handled in the closed or bound state.
+	// No action required here.
+	}
+
+void TL2CAPSAPStateClosed::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Shutdown is permitted by ESOCK on an open (not connected) socket.
+	// Therefore this must be handled in the closed or bound state.
+	aSAP.Socket()->CanClose();
+	}
+	
+void TL2CAPSAPStateClosed::Bound(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EBound));
+	}
+
+TInt TL2CAPSAPStateClosed::NewDataAsyncCallBack(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	//drop
+	return EFalse;
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateChannelPendingBase Implementation
+//
+TL2CAPSAPStateChannelPendingBase::TL2CAPSAPStateChannelPendingBase(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+ 
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateChannelPendingBase::SignalHandlerError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	// Store the error information.
+	aSAP.SetSocketErrorCode(aErrorCode);
+	aSAP.SetSocketErrorAction(aErrorAction);
+	
+	NotifySocketClosed(aSAP);	
+	}
+
+void TL2CAPSAPStateChannelPendingBase::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Set up an error condition to indicate that the connection
+	// has failed.
+	aSAP.SetSocketErrorCode(KErrCouldNotConnect);
+	aSAP.SetSocketErrorAction(MSocketNotify::EErrorConnect);
+	
+	NotifySocketClosed(aSAP);	
+	}
+
+// Events called from the SAP.
+void TL2CAPSAPStateChannelPendingBase::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Enter the disconnecting state and disconnect the Mux.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+	aSAP.SignalHandler().CloseChannelRequest();
+	}
+
+void TL2CAPSAPStateChannelPendingBase::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Enter the closed state and disconnect the Mux.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	aSAP.SignalHandler().CloseChannelRequest();
+	}
+		
+/*************************************************************************/
+//
+// TL2CAPSAPStatePassiveLinkPending Implementation
+//
+TL2CAPSAPStatePassiveLinkPending::TL2CAPSAPStatePassiveLinkPending(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateChannelPendingBase(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+void TL2CAPSAPStatePassiveLinkPending::LinkUp(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Forward the Connect Request event to the signalling state machine.
+	aSAP.SignalHandler().ConnectRequestReceived();
+	
+	// Start security checks.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EPassiveAccessRequestPending));
+	aSAP.StartAccessRequest(*(aSAP.ListeningSAP()));
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateActiveLinkPending Implementation
+//
+TL2CAPSAPStateActiveLinkPending::TL2CAPSAPStateActiveLinkPending(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateChannelPendingBase(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+void TL2CAPSAPStateActiveLinkPending::LinkUp(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// This is the first call to StartAccessRequest() for v2.1 clients.
+	// For outgoing requests, we perform authentication both before the L2CAP
+	// connection is started, and immediately after (for compatibility with
+	// pre 2.1 clients). Here, we just set the required MITM settings; this
+	// has no effect on pre-2.1 clients but this will succeed for 2.1 clients
+	// and the subsequent call is effectively a null-operation.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EActiveSecMode4AccessRequestPending));
+	aSAP.StartAccessRequest(aSAP, ETrue); // indicate that this is outgiong security mode 4
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateActiveSecMode4AccessRequestPending Implementation
+//
+TL2CAPSAPStateActiveSecMode4AccessRequestPending::TL2CAPSAPStateActiveSecMode4AccessRequestPending(CL2CAPSAPStateFactory& aFactory)
+: TL2CAPSAPStateChannelPendingBase(aFactory)
+	{
+	LOG_FUNC
+	}
+
+// Events called from the SAP.
+void TL2CAPSAPStateActiveSecMode4AccessRequestPending::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::FastShutdown(aSAP);
+	}
+	
+void TL2CAPSAPStateActiveSecMode4AccessRequestPending::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::Shutdown(aSAP);
+	}
+
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateActiveSecMode4AccessRequestPending::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::ChannelClosed(aSAP);
+	}
+
+void TL2CAPSAPStateActiveSecMode4AccessRequestPending::SignalHandlerError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::SignalHandlerError(aSAP, aErrorCode, aErrorAction);
+	}
+	
+void TL2CAPSAPStateActiveSecMode4AccessRequestPending::AccessRequestComplete(CL2CAPConnectionSAP& aSAP, TInt aResult) const
+	{
+	LOG_FUNC
+	// Check the result from the security manager.
+	switch(aResult)
+		{
+		case EBTSecManAccessGranted:
+			// Inform the signalling state machine that the connect can be established.
+			aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EActiveChannelRequestPending));
+			aSAP.SignalHandler().OpenChannelRequest();
+			break;
+			
+		case EBTSecManAccessDenied:
+		default:  // Handle any error
+			// Store the error information.
+			aSAP.SetSocketErrorCode(KErrCouldNotConnect);
+			aSAP.SetSocketErrorAction(MSocketNotify::EErrorConnect);
+			
+			// Call the helper method to move to the closed state and 
+			// let the peer know there is a security problem
+			aSAP.SignalHandler().CloseChannelRequest();
+			break;
+		};
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateActiveChannelRequestPending Implementation
+//
+TL2CAPSAPStateActiveChannelRequestPending::TL2CAPSAPStateActiveChannelRequestPending(CL2CAPSAPStateFactory& aFactory)
+: TL2CAPSAPStateChannelPendingBase(aFactory)
+	{
+	LOG_FUNC
+	}
+	
+void TL2CAPSAPStateActiveChannelRequestPending::ChannelOpened(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// A Channel is open but not configured.  Perform security mode 2 security before 
+	// configuring the channel.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EActiveSecMode2AccessRequestPending));
+	
+	// This is the second call to StartAccessRequest(), for pre-v2.1 clients.
+	// For v2.1 clients, the authentication with MITM settings will have
+	// already occurred, and so this call effectively does nothing.
+	aSAP.StartAccessRequest(aSAP);
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStatePassiveAccessRequestPending Implementation
+//
+TL2CAPSAPStatePassiveAccessRequestPending::TL2CAPSAPStatePassiveAccessRequestPending(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateChannelPendingBase(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+// Events called from the SAP.
+void TL2CAPSAPStatePassiveAccessRequestPending::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::FastShutdown(aSAP);
+	}
+	
+void TL2CAPSAPStatePassiveAccessRequestPending::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::Shutdown(aSAP);
+	}
+
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStatePassiveAccessRequestPending::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::ChannelClosed(aSAP);
+	}
+
+void TL2CAPSAPStatePassiveAccessRequestPending::SignalHandlerError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::SignalHandlerError(aSAP, aErrorCode, aErrorAction);
+	}
+
+// Events from the security manager.
+void TL2CAPSAPStatePassiveAccessRequestPending::AccessRequestComplete(CL2CAPConnectionSAP& aSAP, TInt aResult) const
+	{
+	LOG_FUNC
+	// Check the result from the security manager.
+	switch(aResult)
+		{
+		case EBTSecManAccessGranted:
+			// Inform the signalling state machine that the connect can be established.
+			aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EPendingOpen));
+			aSAP.SignalHandler().OpenChannelRequest();
+			break;
+
+		case EBTSecManAccessDenied:
+		default:  // Handle any error
+			// Store the error information.
+			aSAP.SetSocketErrorCode(KErrCouldNotConnect);
+			aSAP.SetSocketErrorAction(MSocketNotify::EErrorConnect);
+
+			// Call the helper method to move to the closed state and 
+			// let the peer know there is a security problem
+			aSAP.SignalHandler().CloseChannelRequest();
+			break;
+		};		
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateActiveSecMode2AccessRequestPending Implementation
+//
+TL2CAPSAPStateActiveSecMode2AccessRequestPending::TL2CAPSAPStateActiveSecMode2AccessRequestPending(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateChannelPendingBase(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+// Events called from the SAP.
+void TL2CAPSAPStateActiveSecMode2AccessRequestPending::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::FastShutdown(aSAP);
+	}
+	
+void TL2CAPSAPStateActiveSecMode2AccessRequestPending::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::Shutdown(aSAP);
+	}
+
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateActiveSecMode2AccessRequestPending::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::ChannelClosed(aSAP);
+	}
+
+void TL2CAPSAPStateActiveSecMode2AccessRequestPending::SignalHandlerError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	aSAP.CancelAccessRequest();
+	TL2CAPSAPStateChannelPendingBase::SignalHandlerError(aSAP, aErrorCode, aErrorAction);
+	}
+
+// Events from the security manager.
+void TL2CAPSAPStateActiveSecMode2AccessRequestPending::AccessRequestComplete(CL2CAPConnectionSAP& aSAP, TInt aResult) const
+	{
+	LOG_FUNC
+	// Check the result from the security manager.
+	switch(aResult)
+		{
+		case EBTSecManAccessGranted:
+			// Inform the signalling state machine that configuration can be started.
+			aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EPendingOpen));
+			aSAP.SignalHandler().ConfigureChannelRequest();
+			break;
+
+		case EBTSecManAccessDenied:
+		default:  // Handle any error
+			// Store the error information.
+			aSAP.SetSocketErrorCode(KErrCouldNotConnect);
+			aSAP.SetSocketErrorAction(MSocketNotify::EErrorConnect);
+
+			// Enter the disconnecting state and disconnect the Mux.
+			aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+			aSAP.SignalHandler().CloseChannelRequest();
+			break;
+		};		
+	}
+	
+/*************************************************************************/
+//
+// TL2CAPSAPStatePendingOpen Implementation
+//
+TL2CAPSAPStatePendingOpen::TL2CAPSAPStatePendingOpen(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateChannelPendingBase(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+
+void TL2CAPSAPStatePendingOpen::ChannelConfigured(CL2CAPConnectionSAP& aSAP,
+	                                              CL2CapChannelConfig& aConfig,
+                                                  CL2CAPMux& aMuxer,
+                                                  TL2CAPPort aLocalPort,
+                                                  TL2CAPPort aRemotePort)
+	{
+	LOG_FUNC
+	TInt rerr = aSAP.CreateDataPlane(aConfig, aMuxer, aLocalPort, aRemotePort);
+	if(rerr == KErrNone)
+		{
+		// This changes the state.
+		aSAP.SocketConnectComplete();
+		}
+	else
+		{
+		// Failed to create the data plane.  Close the connection and error the
+		// socket.
+		DataPlaneError(aSAP, rerr, MSocketNotify::TOperationBitmasks(MSocketNotify::EErrorSend | MSocketNotify::EErrorRecv));
+		}
+	}  
+
+// Events called from the Data Controller.
+void TL2CAPSAPStatePendingOpen::DataPlaneError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	// Store the error condition, and disconnect the signalling.
+	aSAP.SetSocketErrorCode(aErrorCode);
+	aSAP.SetSocketErrorAction(aErrorAction);
+
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+	aSAP.SignalHandler().CloseChannelRequest();
+	}
+			
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateListening Implementation
+//
+TL2CAPSAPStateListening::TL2CAPSAPStateListening(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+// Events called from the SAP.
+void TL2CAPSAPStateListening::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// The listening sap is shutting down.
+	aSAP.SignalHandler().CloseChannelRequest();
+	}
+
+void TL2CAPSAPStateListening::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	aSAP.SignalHandler().CloseChannelRequest();
+	}
+	
+// State Transition Actions.
+void TL2CAPSAPStateListening::Enter(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.Protocol().MuxController().AttachListeningSignalHandler(aSAP.SignalHandler());		
+	}
+
+void TL2CAPSAPStateListening::Exit(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.DeregisterCodService();	// See if there is a Service to remove for CodMan
+	aSAP.Protocol().DecrementListeners();
+	aSAP.DeleteAllClones();
+	
+	// Remove the signal handler from the list of listening SH.
+	aSAP.SignalHandler().iLink.Deque();
+	
+	// Check to see if the stack should be brought down
+	aSAP.Protocol().TryToClose();
+	}
+
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateListening::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Call the helper method to move to the closed state and signal to the
+	// socket that close is complete.
+	NotifySocketClosed(aSAP);	
+	}
+
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateAccepting Implementation
+//
+TL2CAPSAPStateAccepting::TL2CAPSAPStateAccepting(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateOpen(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+ 	
+void TL2CAPSAPStateAccepting::ReconfiguringChannel(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.PauseDataPlane();
+	}
+
+// Events called from the Data Controller.
+void TL2CAPSAPStateAccepting::NewData(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.iNewDataToNotify++;
+	}
+
+void TL2CAPSAPStateAccepting::Start(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EOpen));
+	aSAP.DetachFromListeningSAP();
+	aSAP.StartNewDataAsyncCallBack();
+	}
+
+TInt TL2CAPSAPStateAccepting::NewDataAsyncCallBack(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	// Keep the compiler happy.
+	return KErrNone;
+	}
+	
+void TL2CAPSAPStateAccepting::CanSend(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	PanicInState(EL2CAPUnexpectedDataControllerEvent);
+	}
+
+// State Transition Actions.
+void TL2CAPSAPStateAccepting::Exit(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	}
+	
+/*************************************************************************/
+//
+// TL2CAPSAPStateAwaitingInitialData Implementation
+//
+TL2CAPSAPStateAwaitingInitialData::TL2CAPSAPStateAwaitingInitialData(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPStateOpen(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+ 	
+void TL2CAPSAPStateAwaitingInitialData::ReconfiguringChannel(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.PauseDataPlane();
+	}
+ 	
+ // Events called from the Data Controller.
+void TL2CAPSAPStateAwaitingInitialData::NewData(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SignalHandler().ChannelConfigured();
+	
+	aSAP.iNewDataToNotify++;
+	aSAP.StartNewDataAsyncCallBack();
+	
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EOpen));
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateOpen Implementation
+//
+TL2CAPSAPStateOpen::TL2CAPSAPStateOpen(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+
+void TL2CAPSAPStateOpen::ReconfiguringChannel(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.PauseDataPlane();
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EAwaitingInitialData));
+	}
+
+void TL2CAPSAPStateOpen::ChannelConfigured(CL2CAPConnectionSAP& aSAP,
+	                                       CL2CapChannelConfig& aConfig,
+                                           CL2CAPMux& /*aMuxer*/,
+                                           TL2CAPPort /*aLocalPort*/,
+                                           TL2CAPPort /*aRemotePort*/)
+	{
+	LOG_FUNC
+	//This will be called after a successful reconfigure
+	const TL2CapFecNegotiator& fec = aConfig.FecNegotiator();
+	TL2CapDataControllerConfig* dataConfig = new TL2CapDataControllerConfig(fec.DataControllerConfig());
+
+	if(dataConfig)
+		{
+		aSAP.DataQueue().ResumeSDUQueue(dataConfig,
+									 	aConfig.OutgoingFlushTimeout().Negotiated().FlushTimeoutDuration(),
+		                   				fec.OutgoingMaximumPDUSize(),
+                       				    aConfig.OutgoingMTU().Negotiated().MTU(),
+                       				    aConfig.IncomingMTU().Negotiated().MTU());
+
+		// Adjust the optimal PDU size based on the new configuration values
+		TPckgBuf<TInt> buf;	
+		TInt err = aSAP.GetOption(KSolBtACL, ELMOutboundACLSize, buf);
+
+		TInt optimalPduSize = HL2CapPDU::GetPDUOrFragmentSize(aConfig.OutgoingMTU().Negotiated().MTU(), fec.OutgoingMaximumPDUSize(), (err == KErrNone) ? buf() : 0, aSAP.DataQueue().IsBasicDataVersion());
+		aSAP.DataQueue().SetOptimalPDUSize(optimalPduSize);
+
+		// If this reconfiguration was initiated via an IOCTL complete it.
+		aSAP.TryToCompleteConfigurationIoctl(KErrNone);
+		}
+	else
+		{
+		// If this reconfiguration was initiated via an IOCTL complete it.
+		aSAP.TryToCompleteConfigurationIoctl(KErrNoMemory);
+		DataPlaneError(aSAP, KErrNoMemory, MSocketNotify::TOperationBitmasks(MSocketNotify::EErrorSend | MSocketNotify::EErrorRecv));
+		}
+	}	
+
+// Events called from the SAP.
+TInt TL2CAPSAPStateOpen::Send(CL2CAPConnectionSAP& aSAP, RMBufChain& aData, TUint /*aFlag*/) const
+	{
+	LOG_FUNC
+	TInt rerr = aSAP.DataQueue().Write(aData);
+	if(rerr != KErrNone && rerr != KErrNotReady)
+		{
+		// Need to signal an error for the send operation.
+		aSAP.Socket()->Error(rerr, MSocketNotify::EErrorSend);
+		}
+	return rerr;
+	}
+	
+TInt TL2CAPSAPStateOpen::Read(CL2CAPConnectionSAP& aSAP, RMBufChain& aData) const
+	{
+	LOG_FUNC
+	// The return value is either an error or the number of datagrams read.
+	TInt rValue = KErrNone;
+
+	aSAP.DataQueue().Read(aData);
+	if(aData.Length() > aSAP.DataQueue().MaxIncomingMTU())
+		{
+		// This is larger then the negotiated MRU.  Drop the SDU.
+		aData.Free();
+		rValue = KErrOverflow;
+		}
+	else
+		{
+		rValue = (aData.Length() > 0);
+		}
+	return rValue;
+	}
+
+void TL2CAPSAPStateOpen::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+	
+	aSAP.DataQueue().CloseSDUQueue(CL2CapSDUQueue::EImmediatelyCloseIncomingQueue,
+		                           CL2CapSDUQueue::EDrainOutgoingQueue);
+	}
+
+void TL2CAPSAPStateOpen::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// This needs to be shutdown within this stack frame.
+	// Move into the Closed state (Note. This transition de-activates 
+	// park mode).  Attempt to send a Disconnect Requests, and delete 
+	// the data plane. 
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	aSAP.SignalHandler().CloseChannelRequest();
+	aSAP.SDUQueueClosed();	
+	}
+
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateOpen::CloseOutgoingSDUQueue(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+
+	// Close the Outgoing SDU queue.	
+	aSAP.DataQueue().CloseSDUQueue(CL2CapSDUQueue::EDrainIncomingQueue,
+		                           CL2CapSDUQueue::EImmediatelyCloseOutgoingQueue);
+	}	
+
+void TL2CAPSAPStateOpen::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+
+	// Close the Outgoing SDU queue.	
+	aSAP.DataQueue().CloseSDUQueue(CL2CapSDUQueue::EDrainIncomingQueue,
+		                           CL2CapSDUQueue::EImmediatelyCloseOutgoingQueue);
+	}
+
+void TL2CAPSAPStateOpen::SignalHandlerError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+
+	CL2CapSDUQueue::TIncomingSDUQueueCloseAction icAct = (aErrorAction & MSocketNotify::EErrorRecv) ?
+	                                                     CL2CapSDUQueue::EImmediatelyCloseIncomingQueue :
+	                                                     CL2CapSDUQueue::EDrainIncomingQueue;
+
+	CL2CapSDUQueue::TOutgoingSDUQueueCloseAction ogAct = (aErrorAction & MSocketNotify::EErrorSend) ?
+	                                                     CL2CapSDUQueue::EImmediatelyCloseOutgoingQueue :
+	                                                     CL2CapSDUQueue::EDrainOutgoingQueue;
+	                                                   
+	// Close the queue. Drain the queues according to the
+	// error action.
+	aSAP.DataQueue().CloseSDUQueue(icAct, ogAct);
+
+	// Store the error information.
+	aSAP.SetSocketErrorCode(aErrorCode);
+	aSAP.SetSocketErrorAction(aErrorAction);
+	}
+
+
+// Events called from the Data Controller.
+void TL2CAPSAPStateOpen::NewData(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.iNewDataToNotify++;
+	aSAP.StartNewDataAsyncCallBack();
+	}
+	
+TInt TL2CAPSAPStateOpen::NewDataAsyncCallBack(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Datagram i/f -- pass up no. of packets.
+	TUint16 newData = aSAP.iNewDataToNotify;
+	if(newData)
+		{
+		aSAP.iNewDataToNotify = 0;
+		aSAP.Socket()->NewData(newData);
+		}
+	return EFalse;
+	}
+	
+void TL2CAPSAPStateOpen::CanSend(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.Socket()->CanSend();
+	}
+
+// Events called from the Data Controller.
+void TL2CAPSAPStateOpen::DataPlaneError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	// Store the error condition, and disconnect the signalling.
+	aSAP.SetSocketErrorCode(aErrorCode);
+	aSAP.SetSocketErrorAction(aErrorAction);
+
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EDisconnecting));
+
+	// Close the data plane.
+	aSAP.SDUQueueClosed();
+	aSAP.SignalHandler().CloseChannelRequest();
+	}
+	
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateDisconnecting Implementation
+//
+TL2CAPSAPStateDisconnecting::TL2CAPSAPStateDisconnecting(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+ 
+void TL2CAPSAPStateDisconnecting::Start(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// We do the same here as in the EClosed state, as under exceptional
+	// circumstances a slight race will result in the Start() coming in
+	// this state.
+	StartCalledWhileDisconnected(aSAP);
+	}
+
+// Events called from the SAP.
+TInt TL2CAPSAPStateDisconnecting::Send(CL2CAPConnectionSAP& /*aSAP*/, RMBufChain& /*aData*/, TUint /*aFlag*/) const
+	{
+	LOG_FUNC
+	return KErrNotReady; // Indicate that no data has been sent.
+	}
+
+TInt TL2CAPSAPStateDisconnecting::Read(CL2CAPConnectionSAP& aSAP, RMBufChain& aData) const
+	{
+	LOG_FUNC
+	// The return value is either an error or the number of datagrams read.
+	TInt rValue = KErrNone;
+
+	// Check if the queue is closed.
+	if(!aSAP.IsSDUQueueClosed())
+		{
+		aSAP.DataQueue().Read(aData);
+		if(aData.Length() > aSAP.DataQueue().MaxIncomingMTU())
+			{
+			// This is larger then the negotiated MRU.  Drop the SDU.
+			aData.Free();
+			rValue = KErrOverflow;
+			}
+		else
+			{
+			rValue = (aData.Length() > 0);	
+			}
+		}
+	return rValue;
+	}
+
+void TL2CAPSAPStateDisconnecting::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	LOG(_L("L2CAP disconnecting state: shutdown"));
+	
+	// If the queue is still active, indicate that the incoming
+	// queue no longer needs to be drained.
+	if(!aSAP.IsSDUQueueClosed())
+		{
+		LOG(_L(" -- need to close SDU queue"));
+
+		aSAP.DataQueue().CloseSDUQueue(CL2CapSDUQueue::EImmediatelyCloseIncomingQueue,
+		                               CL2CapSDUQueue::EDrainOutgoingQueue);
+		}
+	}
+
+void TL2CAPSAPStateDisconnecting::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	LOG(_L("L2CAP disconnecting state: fast shutdown"));
+
+	// This needs to be shutdown within this stack frame.
+	// Delete the data plane, attempt to send a Disconnect Requests
+	// and move into the Closed state.	
+	aSAP.SignalHandler().CloseChannelRequest();
+
+	// This transition removes the park mode override.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	aSAP.SDUQueueClosed();	
+	}
+
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateDisconnecting::ChannelClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// If the data plane is closed there is nothing more to be done.
+	if(aSAP.IsSDUQueueClosed())
+		{
+		// Call the helper method to move to the closed state and signal to the
+		// socket that close is complete.
+		NotifySocketClosed(aSAP);	
+		}
+	}
+
+void TL2CAPSAPStateDisconnecting::SignalHandlerError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	// Store the error information.
+	aSAP.SetSocketErrorCode(aErrorCode);
+	aSAP.SetSocketErrorAction(aErrorAction);
+
+	// The signalling has errored so a Disconnect Complete is no longer
+	// expected.
+	if(aSAP.IsSDUQueueClosed())
+		{
+		// Call the helper method to move to the closed state and signal to the
+		// socket that close is complete.
+		NotifySocketClosed(aSAP);	
+		}
+	else
+		{
+		// The SDU queue is still active.  Ensure the correct queues are getting drained.
+		CL2CapSDUQueue::TIncomingSDUQueueCloseAction icAct = (aErrorAction & MSocketNotify::EErrorRecv) ?
+		                                                     CL2CapSDUQueue::EImmediatelyCloseIncomingQueue :
+		                                                     CL2CapSDUQueue::EDrainIncomingQueue;
+
+		CL2CapSDUQueue::TOutgoingSDUQueueCloseAction ogAct = (aErrorAction & MSocketNotify::EErrorSend) ?
+		                                                     CL2CapSDUQueue::EImmediatelyCloseOutgoingQueue :
+		                                                     CL2CapSDUQueue::EDrainOutgoingQueue;
+		                                                   
+		// Close the queue. Drain the queues according to the
+		// error action.
+		aSAP.DataQueue().CloseSDUQueue(icAct, ogAct);
+		}
+	}
+
+void TL2CAPSAPStateDisconnecting::CloseOutgoingSDUQueue(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Close the Outgoing SDU queue.	
+	aSAP.DataQueue().CloseSDUQueue(CL2CapSDUQueue::EImmediatelyCloseIncomingQueue,
+		                           CL2CapSDUQueue::EImmediatelyCloseOutgoingQueue);
+	}	
+
+// Events called from the Data Controller.
+void TL2CAPSAPStateDisconnecting::SDUQueueClosed(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// The SDU queue has been disconnected.  Check if Disconnect signalling 
+	// is complete.
+	if(aSAP.SignalHandler().IsChannelClosed())
+		{
+		// Call the helper method to move to the closed state and signal to the
+		// socket that close is complete.
+		NotifySocketClosed(aSAP);	
+		}
+	else
+		{
+		// Signal disconnect to the signal handler.
+		aSAP.SignalHandler().CloseChannelRequest();
+		}
+	}
+
+
+void TL2CAPSAPStateDisconnecting::DataPlaneError(CL2CAPConnectionSAP& aSAP, TInt aErrorCode, MSocketNotify::TOperationBitmasks aErrorAction) const
+	{
+	LOG_FUNC
+	// Store the error condition, and disconnect the signalling.
+	aSAP.SetSocketErrorCode(aErrorCode);
+	aSAP.SetSocketErrorAction(aErrorAction);
+
+	// Close the data plane.
+	aSAP.SDUQueueClosed();
+	}
+
+void TL2CAPSAPStateDisconnecting::NewData(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// Data received in this state can be silently dropped.
+	}
+
+TInt TL2CAPSAPStateDisconnecting::NewDataAsyncCallBack(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	//Note we may have data received before moving into the 
+	//disconnect state that we haven't yet informed ESock about
+	
+	//Datagram i/f -- pass up no. of packets
+	TUint16 newData = aSAP.iNewDataToNotify;
+	if(newData)
+		{
+		aSAP.iNewDataToNotify = 0;
+		aSAP.Socket()->NewData(newData);
+		}
+	return EFalse; 
+	}
+
+void TL2CAPSAPStateDisconnecting::CanSend(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Check that the SDU queue is still open, and a Shutdown
+	// has not been received.
+	if(!aSAP.IsSDUQueueClosed() && aSAP.ShutdownReceived() == CL2CAPConnectionSAP::ESAPShutdownNone)
+		{
+		aSAP.Socket()->CanSend();
+		}
+	}
+
+void TL2CAPSAPStateDisconnecting::ChannelConfigured(CL2CAPConnectionSAP& /*aSAP*/,
+	                                   CL2CapChannelConfig& /*aConfig*/,
+                                       CL2CAPMux& /*aMuxer*/,
+                                       TL2CAPPort /*aLocalPort*/,
+                                       TL2CAPPort /*aRemotePort*/)
+	{
+	LOG_FUNC
+	// Drop this event as the SAP is closing.  The SAP signal handler
+	// is still open to handle the exchange with the remote until
+	// the connection is closed.
+	}
+
+void TL2CAPSAPStateDisconnecting::ReconfiguringChannel(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// Drop this event as the SAP is closing.  The SAP signal handler
+	// is still open to handle the exchange with the remote until
+	// the connection is closed.
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateError Implementation
+//
+TL2CAPSAPStateError::TL2CAPSAPStateError(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+
+// Events called from the SAP.
+void TL2CAPSAPStateError::Start(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	}
+	
+TInt TL2CAPSAPStateError::Ioctl(CL2CAPConnectionSAP& aSAP, TUint /*aLevel*/, TUint /*aName*/, TDes8* /*aOption*/) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	return KErrNotReady;
+	}
+	
+void TL2CAPSAPStateError::CancelIoctl(CL2CAPConnectionSAP& aSAP, TUint /*aLevel*/, TUint /*aName*/) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	}
+	
+void TL2CAPSAPStateError::IoctlComplete(CL2CAPConnectionSAP& aSAP, TInt /*aErr*/, TUint /*aLevel*/, TUint /*aName*/, TDesC8* /*aBuf*/) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	}
+	
+
+void TL2CAPSAPStateError::ActiveOpen(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	}
+	
+TInt TL2CAPSAPStateError::PassiveOpen(CL2CAPConnectionSAP& aSAP, TUint /*aQueSize*/) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	return KErrNotReady;	
+	}
+	
+void TL2CAPSAPStateError::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// The socket wishes to close the SAP, signal can close.
+	aSAP.Socket()->CanClose();
+	}
+	
+void TL2CAPSAPStateError::FastShutdown(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// The SAP is about to be deleted by the socket. No action required in this state.
+	}
+	
+
+TInt TL2CAPSAPStateError::Send(CL2CAPConnectionSAP& aSAP, RMBufChain& /*aData*/, TUint /*aFlag*/) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	return KErrNotReady; // Indicate that no data has been sent.
+	}
+	
+TInt TL2CAPSAPStateError::Read(CL2CAPConnectionSAP& aSAP, RMBufChain& /*aData*/) const
+	{
+	LOG_FUNC
+	// Error the socket to error/complete the outstanding request.
+	aSAP.Socket()->Error(aSAP.SocketErrorCode(), aSAP.SocketErrorAction());
+	return KErrNotReady;
+	}
+	
+// Events called from the SAP Signal Handler.
+void TL2CAPSAPStateError::ChannelClosed(CL2CAPConnectionSAP& /*aSAP*/) const
+	{
+	LOG_FUNC
+	// Already in the error state so no need to transition.
+	// Consume the event.
+	}
+	
+// State Transition Actions.
+void TL2CAPSAPStateError::Enter(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Set the error action to error all requests from the socket.
+	aSAP.SetSocketErrorAction(MSocketNotify::EErrorAllOperations);
+	aSAP.DeregisterCodService();	// See if there is a Service to remove for CodMan
+	}
+
+/*************************************************************************/
+//
+// TL2CAPSAPStateBound Implementation
+//
+TL2CAPSAPStateBound::TL2CAPSAPStateBound(CL2CAPSAPStateFactory& aFactory)
+ : TL2CAPSAPState(aFactory)
+ 	{
+	LOG_FUNC
+ 	}
+ 	
+TInt TL2CAPSAPStateBound::PassiveOpen(CL2CAPConnectionSAP& aSAP, TUint aQueSize) const
+	{
+	LOG_FUNC
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EListening));
+
+	// would be nice to use Listening::Enter but return path of TInt is lost
+	TInt rerr = aSAP.Protocol().IncrementListeners();
+
+	aSAP.RegisterCodService();	// See if there is a Service set for CodMan
+
+	if(rerr == KErrNone)
+		{
+		aSAP.iMaxAcceptingQCount = static_cast<TUint8>(aQueSize);
+		__ASSERT_DEBUG(aSAP.iClones.Count() == 0, PanicInState(EL2CAPUnexpectedSocketEvent));
+		}
+	return rerr;
+	}
+
+// State Transition Actions.
+void TL2CAPSAPStateBound::Enter(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	aSAP.Protocol().MuxController().AttachBoundSignalHandler(aSAP.SignalHandler());
+	}
+	
+void TL2CAPSAPStateBound::Exit(CL2CAPConnectionSAP& aSAP) const	
+	{
+	LOG_FUNC
+	// Remove the signal handler from the list of bound SH.
+	aSAP.SignalHandler().iLink.Deque();	
+	
+	// Check to see if the stack needs to be brought down
+	aSAP.Protocol().TryToClose();
+	}
+
+void TL2CAPSAPStateBound::FastShutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Shutdown is permitted by ESOCK on an open (not connected) socket.
+	// Therefore this must be handled in the closed or bound state.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	}
+
+void TL2CAPSAPStateBound::Shutdown(CL2CAPConnectionSAP& aSAP) const
+	{
+	LOG_FUNC
+	// Shutdown is permitted by ESOCK on an open (not connected) socket.
+	// Therefore this must be handled in the closed or bound state.
+	aSAP.SetState(iFactory.GetState(CL2CAPSAPStateFactory::EClosed));
+	aSAP.Socket()->CanClose();
+	}
+
+
+/*************************************************************************/
+//
+// CL2CAPSAPStateFactory Implementation
+//
+CL2CAPSAPStateFactory::CL2CAPSAPStateFactory()
+	{
+	LOG_FUNC
+	}
+
+CL2CAPSAPStateFactory::~CL2CAPSAPStateFactory()
+	{
+	LOG_FUNC
+	// Destroy all the state objects
+	iStates.DeleteAll();
+	}
+	
+CL2CAPSAPStateFactory* CL2CAPSAPStateFactory::NewL()
+	{
+	LOG_STATIC_FUNC
+	CL2CAPSAPStateFactory* factory= new (ELeave) CL2CAPSAPStateFactory();
+	CleanupStack::PushL(factory);
+
+	// Create all the new states
+	factory->iStates[EClosed]								= new (ELeave) TL2CAPSAPStateClosed(*factory);
+	factory->iStates[EPassiveLinkPending]					= new (ELeave) TL2CAPSAPStatePassiveLinkPending(*factory);
+	factory->iStates[EActiveLinkPending]					= new (ELeave) TL2CAPSAPStateActiveLinkPending(*factory);
+	factory->iStates[EPassiveAccessRequestPending]			= new (ELeave) TL2CAPSAPStatePassiveAccessRequestPending(*factory);
+	factory->iStates[EActiveSecMode2AccessRequestPending]	= new (ELeave) TL2CAPSAPStateActiveSecMode2AccessRequestPending(*factory);
+	factory->iStates[EPendingOpen]							= new (ELeave) TL2CAPSAPStatePendingOpen(*factory);
+	factory->iStates[EListening]							= new (ELeave) TL2CAPSAPStateListening(*factory);
+	factory->iStates[EAccepting]							= new (ELeave) TL2CAPSAPStateAccepting(*factory);
+	factory->iStates[EAwaitingInitialData]					= new (ELeave) TL2CAPSAPStateAwaitingInitialData(*factory);
+	factory->iStates[EOpen]									= new (ELeave) TL2CAPSAPStateOpen(*factory);
+	factory->iStates[EDisconnecting]						= new (ELeave) TL2CAPSAPStateDisconnecting(*factory);
+	factory->iStates[EError]								= new (ELeave) TL2CAPSAPStateError(*factory);
+	factory->iStates[EBound]								= new (ELeave) TL2CAPSAPStateBound(*factory);
+	factory->iStates[EActiveSecMode4AccessRequestPending]	= new (ELeave) TL2CAPSAPStateActiveSecMode4AccessRequestPending(*factory);
+	factory->iStates[EActiveChannelRequestPending]			= new (ELeave) TL2CAPSAPStateActiveChannelRequestPending(*factory);
+
+	CleanupStack::Pop();
+	return factory;
+	}
+
+TL2CAPSAPState& CL2CAPSAPStateFactory::GetState(const TStates aState) const
+	{
+	LOG_FUNC
+	__ASSERT_DEBUG(aState != EMaxState, Panic(EL2CAPSAPMuxerStateOutOfBounds));
+	return *iStates[aState];
+	}
+
+TInt CL2CAPSAPStateFactory::StateIndex(const TL2CAPSAPState* aState) const
+	{
+	LOG_FUNC
+	TInt state;
+	for (state = 0; state < EMaxState; state++)
+		{
+		if (iStates[state] == aState)
+			{
+			return state;
+			}
+		}
+	
+	return KL2UnknownState;
+	}
+