diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/l2cap/l2sapstates.cpp --- /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 + +#include + +#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 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(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; + } +