diff -r 8d540f55e491 -r 425d8f4f7fa5 linklayerprotocols/tundriver/src/tundriverflow.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linklayerprotocols/tundriver/src/tundriverflow.cpp Wed Sep 15 00:18:51 2010 +0300 @@ -0,0 +1,510 @@ +/** +* Copyright (c) 2010 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: +* Flow implementation for data path for tunnel driver. +* +* +*/ + +/** + @file tundriverflow.cpp + @internalTechnology +*/ + +#include +#include +#include +#include +#include + +#include "ss_subconnflow.h" +#include +#include "tundriverflow.h" +#include "tundriverbinder.h" +#include "tundriverprovision.h" + +using namespace Messages; +using namespace MeshMachine; +using namespace ESock; + +#ifdef SYMBIAN_TRACE_ENABLE +_LIT8(KNif,"tundriver"); +#endif + +CTunDriverSubConnectionFlowFactory* CTunDriverSubConnectionFlowFactory::NewL(TAny* aConstructionParameters) +/** +* CTunDriverSubConnectionFlowFactory::NewL constructs a Default SubConnection Flow Factory +* @param aConstructionParameters construction data passed by ECOM +* @returns pointer to a constructed factory object. +*/ + { + CTunDriverSubConnectionFlowFactory* ptr = new (ELeave) CTunDriverSubConnectionFlowFactory(TUid::Uid(KTunDriverFlowImplementationUid), *(reinterpret_cast(aConstructionParameters))); + return ptr; + } + + +CTunDriverSubConnectionFlowFactory::CTunDriverSubConnectionFlowFactory(TUid aFactoryId, CSubConnectionFlowFactoryContainer& aParentContainer) +: CSubConnectionFlowFactoryBase(aFactoryId, aParentContainer) +/** +* CTunDriverSubConnectionFlowFactory::CTunDriverSubConnectionFlowFactory is a Default SubConnection Flow Factory +* @param aFactoryId ECOM Implementation Id +* @param aParentContainer Object Owner +*/ + { + } + +CSubConnectionFlowBase* CTunDriverSubConnectionFlowFactory::DoCreateFlowL(CProtocolIntfBase* aProtocolIntf, TFactoryQueryBase& aQuery) +/** +* CTunDriverSubConnectionFlowFactory::DoCreateFlowL will create SubConnection Flow. +* @param aFactoryId ECOM Implementation Id +* @param aParentContainer Object Owner +*/ + { + const TDefaultFlowFactoryQuery& query = static_cast(aQuery); + return CTunDriverSubConnectionFlow::NewL(*this, query.iSCprId, aProtocolIntf); + } + +CTunDriverSubConnectionFlow::CTunDriverSubConnectionFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf) +: CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf) +/** +* CTunDriverSubConnectionFlow::CTunDriverSubConnectionFlow is a Default Constructor +* @param aFactoryId ECOM Implementation Id +* @param aParentContainer Object Owner +*/ + { + __FLOG_OPEN(KCFNodeTag, KNif); + LOG_NODE_CREATE(KNif, CTunDriverSubConnectionFlow); + } + +CTunDriverSubConnectionFlow::~CTunDriverSubConnectionFlow() +/** +* CTunDriverSubConnectionFlowFactory::~CTunDriverSubConnectionFlow is a Default destructor +* @param aFactoryId ECOM Implementation Id +* @param aParentContainer Object Owner +*/ + { + delete iBinder4; + iBinder4 = NULL; +#ifdef IPV6SUPPORT + delete iBinder6; + iBinder6 = NULL; +#endif + LOG_NODE_DESTROY(KNif, CTunDriverSubConnectionFlow); + __FLOG_CLOSE; + } + +CTunDriverSubConnectionFlow* CTunDriverSubConnectionFlow::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf) +/** +* CTunDriverSubConnectionFlowFactory::NewL is a first phase Constructor. +* @param aFactoryId ECOM Implementation Id +* @param aParentContainer Object Owner +*/ + { + CTunDriverSubConnectionFlow* flow = new (ELeave) CTunDriverSubConnectionFlow(aFactory, aSubConnId, aProtocolIntf); + return flow; + } + +void CTunDriverSubConnectionFlow::FlowDown(TInt aError, TInt aAction /*= MNifIfNotify::EDisconnect*/) +/** +* CTunDriverSubConnectionFlowFactory::FlowDown will post the message. +* @param aError obtained from the upper CF Layer. +* @param aAction and the action message for aError. +*/ + { + PostFlowDownMessage(aError, aAction); + } + +void CTunDriverSubConnectionFlow::Progress(TInt aStage, TInt aError) +/** +* CTunDriverSubConnectionFlowFactory::Progress Binder requesting a Progress() message be sent to SCPR +* @param aStage and the action message for aError. +* @param aError obtained from the upper CF Layer. +*/ + { + PostProgressMessage(aStage, aError); + } + +const TTunDriverIp4Provision* CTunDriverSubConnectionFlow::Ip4Provision() const +/** +* CTunDriverSubConnectionFlowFactory::Ip4Provision +* @param +* @return iIp4Provision. +*/ + { + ASSERT(iProvision); + return &iProvision->iIp4Provision; + } + +#ifdef IPV6SUPPORT +const TTunDriverIp6Provision* CTunDriverSubConnectionFlow::Ip6Provision() const +/** +* CTunDriverSubConnectionFlowFactory::Ip6Provision +* @param +* @return iIp6Provision. +*/ + { + ASSERT(iProvision); + return &iProvision->iIp6Provision; + } +#endif + +//-========================================================= +// Messages::ANode methods +//-========================================================= + +#define __FRAMEWORK_PRODUCTION_ERRORHANDLING(c,p) (void)((c)||(p,0)) +void CTunDriverSubConnectionFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage) +/** +* CTunDriverSubConnectionFlowFactory::ReceivedL called on incoming SCPR Messages. +* CTunDriverSubConnectionFlow functions will be called Based on message type +* @param aCFMessage message base +*/ + { + #ifdef __FLOG_ACTIVE + TAny* senderAddr = NULL; + const TNodeId* senderNodeId = address_cast(&aSender); + __ASSERT_DEBUG(senderNodeId!=NULL,User::LeaveIfError(KErrCorrupt)); + senderAddr = senderNodeId->Ptr(); + __FLOG_4(_L8("CTunDriverSubConnectionFlow(%x):\tReceivedL() Sender Id: %x, Msg Realm: %X, Msg ID: %d"), this, senderAddr, aMessage.MessageId().Realm(), aMessage.MessageId().MessageId()); + #endif + + CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage); + if (aMessage.IsMessage()) + { + SubConnectionError(static_cast(aMessage).iValue); + } + else if (TEChild::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case TEChild::TCancel::EId: + CancelFlow(KErrCancel); + case TEChild::TDestroy::EId : + Destroy(); + break; + default: + ASSERT(EFalse); + } + } + else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm()) + { + switch (aMessage.MessageId().MessageId()) + { + case TCFDataClient::TStart::EId : + StartFlowL(); + break; + case TCFDataClient::TStop::EId : + StopFlow(static_cast(aMessage).iValue); + break; + case TCFDataClient::TProvisionConfig::EId: + ProvisionConfig(static_cast(aMessage).iConfig); + break; + case TCFDataClient::TBindTo::EId: + { + TCFDataClient::TBindTo& bindToReq = message_cast(aMessage); + __FRAMEWORK_PRODUCTION_ERRORHANDLING(bindToReq.iNodeId.IsNull(),User::LeaveIfError(KErrNotSupported)); + RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete().CRef()); + } + break; + default: + ASSERT(EFalse); + } + } + else + { + User::Leave(KErrNotSupported); + } + } + +void CTunDriverSubConnectionFlow::StartFlowL() +/** +* CTunDriverSubConnectionFlowFactory::StartFlowL starts the flow on receiving the message TStart. +* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL +*/ + { + __FLOG(_L8("CTunDriverSubConnectionFlow:\tStartFlowL()")); + + if(iMMState == EStarted) + { + //Flow can be started multiple times. + //For example a start may fail on an upper layer in which case the upper layer will not be able + //to stop our layer and we need to accept start again. + PostProgressMessage(KLinkLayerOpen, KErrNone); + PostDataClientStartedMessage(); + return; + } + iMMState = EStarted; + + // If the processing of the ProvisionConfig message failed earlier, send the error response + // here to the StartFlow message as there is no response to ProvisionConfig. + User::LeaveIfError(iSavedError); + + PostProgressMessage(KLinkLayerOpen, KErrNone); + PostDataClientStartedMessage(); + iBinder4->StartSending(); +#ifdef IPV6SUPPORT + if(iBinder6) + { + iBinder6->StartSending(); + } +#endif + } + +void CTunDriverSubConnectionFlow::CancelFlow(TInt aError) +/** +* CTunDriverSubConnectionFlowFactory::CancelFlow cancels the flow on receiving the message TCancel. +* It will post the message as KErrCancel. +* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL +*/ + { + __FLOG_1(_L8("CTunDriverSubConnectionFlow:\tCancelFlow(%d)"), aError); + + if(iMMState == EStarted) + { + PostFlowDownMessage(aError); + } + } + +void CTunDriverSubConnectionFlow::StopFlow(TInt aError) +/** +* CTunDriverSubConnectionFlowFactory::StopFlow stops the flow on receiving the message TStop. +* It will post the message as KLinkLayerClosed and KErrCancel. +* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL +*/ + { + __FLOG_1(_L8("CTunDriverSubConnectionFlow:\tStopFlow(%d)"), aError); + + PostProgressMessage(KLinkLayerClosed, aError); + iMMState = EStopped; + PostFlowDownMessage(aError); + } + +void CTunDriverSubConnectionFlow::ProvisionConfig(const ESock::RMetaExtensionContainerC& aConfigData) +/** +* CTunDriverSubConnectionFlowFactory::Provisionconfig on receipt of the ProvisionConfig message, the pointer contained within it is stored +* in iAccessPointConfig and the information contained within the iAccessPointConfig array is validated: +* CTunDriverProtoProvision must be present. It is added by the TunDriverMCPr and populated from CommsDat. +* It is a 'C' class to take advantage of zero initialisation. +* Any errors are saved in iSavedError - there is no response to ProvisionConfig, +* so an error response is sent later to StartFlow message. +* +* on receipt of TCFDataClient::TStart: +* iSavedError is checked and, if non-zero, an Error message is sent to the SCPr +* TunDriverAgentProvision must be present. It is added by the TunDriverAgentHandler and populated via calls +* to the Agent. It is a 'T' class because it requires no zero initialisation. If missing, +* an Error message is signalled to the SCPr. +* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL +* @param aData pointer to provisioning structure +*/ + { + __FLOG_0(_L8("CTunDriverSubConnectionFlow:\tProvisionConfig message received")); + iSavedError = KErrNone; + iAccessPointConfig.Close(); + iAccessPointConfig.Open(aConfigData); + + const CTunDriverProtoProvision* provision = static_cast(AccessPointConfig().FindExtension( + STypeId::CreateSTypeId(CTunDriverProtoProvision::EUid, CTunDriverProtoProvision::ETypeId))); + __FRAMEWORK_PRODUCTION_ERRORHANDLING(provision!=NULL,iSavedError = KErrCorrupt); + + iProvision = provision; + } + +void CTunDriverSubConnectionFlow::Destroy() +/** +* CTunDriverSubConnectionFlowFactory::Destroy +* Request from SCPR to destroy +* This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL +*/ + { + DeleteThisFlow(); + } + +void CTunDriverSubConnectionFlow::SubConnectionGoingDown() +/** +* CTunDriverSubConnectionFlowFactory::SubConnectionGoingDown +* Request from Agemt SCPR +*/ + { + __FLOG(_L8("CTunDriverSubConnectionFlow:\tSubConnectionGoingDown")); + } + +void CTunDriverSubConnectionFlow::SubConnectionError(TInt /*aError*/) +/** +* CTunDriverSubConnectionFlowFactory::SubConnectionError +* Request from Agemt SCPR +*/ + { + __FLOG(_L8("CTunDriverSubConnectionFlow:\tSubConnectionError")); + } + +MFlowBinderControl* CTunDriverSubConnectionFlow::DoGetBinderControlL() +/** +* CTunDriverSubConnectionFlowFactory::DoGetBinderControlL Called by upper layer for binding +* Request from Agemt SCPR +* @return MFlowBinderControl instance +*/ + { + __FLOG(_L8("CTunDriverSubConnectionFlow::DoGetBinderControlL")); + return this; + } + +//-========================================================= +// MFlowBinderControl methods +// + +MLowerControl* CTunDriverSubConnectionFlow::GetControlL(const TDesC8& aProtocol) +/** +* CTunDriverSubConnectionFlow::GetControlL +* Create and return an MLowerControl instance of the specified binder type. +* Called from upper layer during binding procedure. +* @param aProtocol Protocol type of the binder +* @return MLowerControl instance of the protocol type +*/ + { + MLowerControl* lowerControl = NULL; + __FLOG(_L8("CTunDriverSubConnectionFlow:\tGetLowerControlL(KProtocol4)")); + if(aProtocol.Compare(KProtocol4()) == 0) + { + iBinder4 = CTunDriverBinder4::NewL(*this); + lowerControl = iBinder4; + } +#ifdef IPV6SUPPORT + else + if (aProtocol.CompareF(KProtocol6()) == 0) + { + __FLOG(_L8("CTunDriverSubConnectionFlow::GetLowerControlL(KProtocol6)- Should Return KErrNotSupported")); + iBinder6 = CTunDriverBinder6::NewL(*this); + lowerControl = iBinder6; + } +#endif + return lowerControl; + } + +MLowerDataSender* CTunDriverSubConnectionFlow::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, MUpperControl* aControl) +/** +* CTunDriverSubConnectionFlow::BindL Create and return an MLowerDataSender instance of the specified protocol type. +* This is bound to the specified upper layer objects. +* Called from upper layer to bind to this layer. +* @param aProtocol Protocol type of the binder (same as in GetControlL()) +* @param aReceiver upper layer's MUpperDataReceiver instance for this binder to associate with +* @param aControl upper layer's MUpperControl instance for this binder to associate with +* @return MLowerDataSender instance +*/ + { + __FLOG(_L8("CTunDriverSubConnectionFlow:\tBindL()")); + + MLowerDataSender* lowerDataSender = NULL; + + if(aProtocol.CompareF(KProtocol4()) == 0) + { + lowerDataSender = iBinder4->Bind(*aReceiver, *aControl); + } +#ifdef IPV6SUPPORT + else + if (aProtocol.CompareF(KProtocol6()) == 0) + { + lowerDataSender = iBinder6->Bind(*aReceiver, *aControl); + } +#endif + if(lowerDataSender != NULL) + { + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef()); + } + return lowerDataSender; + } + +void CTunDriverSubConnectionFlow::Unbind(MUpperDataReceiver* aReceiver, MUpperControl* aControl) +/** +* CTunDriverSubConnectionFlow::Unbind will Unbind from the upper layer. +* Called from the upper layer during unbinding. +* @param aReceiver +* @param aControl +*/ + { + __FLOG(_L8("CTunDriverSubConnectionFlow:\tUnbind()")); + if (iBinder4 && iBinder4->MatchesUpperControl(aControl)) + { + iBinder4->Unbind(*aReceiver, *aControl); + delete iBinder4; + iBinder4 = NULL; + } +#ifdef IPV6SUPPORT + if (iBinder6 && iBinder6->MatchesUpperControl(aControl)) + { + iBinder6->Unbind(*aReceiver, *aControl); + delete iBinder6; + iBinder6 = NULL; + } +#endif + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef()); + } + +ESock::CSubConnectionFlowBase* CTunDriverSubConnectionFlow::Flow() +/** +* CTunDriverSubConnectionFlow::Flow will Return the flow object corresponding to the MFlowBinderControl +* Called from the UpperLayer get the instance of the flow. +*/ + { + return this; + } + +void CTunDriverSubConnectionFlow::PostProgressMessage(TInt aStage, TInt aError) +/* +* CTunDriverSubConnectionFlow::PostProgressMessage will send the state change message with the param values. +* +*/ + { + iSubConnectionProvider.PostMessage(Id(), TCFMessage::TStateChange(Elements::TStateChange(aStage, aError)).CRef()); + } + +void CTunDriverSubConnectionFlow::PostDataClientStartedMessage() +/* +* CTunDriverSubConnectionFlow::PostDataClientStartedMessage will send the started message with the param values. +*/ + { + iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef()); + } + +void CTunDriverSubConnectionFlow::PostFlowDownMessage(TInt aError, TInt aAction /*= MNifIfNotify::EDisconnect*/) +/* +* CTunDriverSubConnectionFlow::PostFlowDownMessage will send the DataClient Down message with the param values. +*/ + { + if (iMMState == EStarted) + { + iMMState = EStopped; + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, aAction).CRef()); + } + else + { + iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef()); + } + } + +void CTunDriverSubConnectionFlow::MaybePostDataClientIdle() +/* +* CTunDriverSubConnectionFlow::MaybePostDataClientIdle will send the Idle message with the param values. +*/ + { + // Can only send DataClientIdle when the upper layer has unbound and the flow is stopped + if( iBinder4 == NULL +#ifdef IPV6SUPPORT + || iBinder6 == NULL +#endif + ) + { + iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef()); + } + } +