// 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;
	}

