linklayerprotocols/tundriver/src/tundriverflow.cpp
branchRCL_3
changeset 23 425d8f4f7fa5
--- /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 <e32std.h>
+#include <ecom/ecom.h>
+#include <ecom/implementationproxy.h>
+#include <elements/nm_messages_base.h>
+#include <elements/nm_messages_child.h>
+
+#include "ss_subconnflow.h"
+#include <comms-infras/ss_log.h>
+#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<CSubConnectionFlowFactoryContainer*>(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<const TDefaultFlowFactoryQuery&>(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<TNodeId>(&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<TEBase::TError>())
+        {
+        SubConnectionError(static_cast<TEBase::TError&>(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<TCFDataClient::TStop&>(aMessage).iValue);
+            break;
+        case TCFDataClient::TProvisionConfig::EId:
+            ProvisionConfig(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
+            break;
+        case TCFDataClient::TBindTo::EId:
+            {
+            TCFDataClient::TBindTo& bindToReq = message_cast<TCFDataClient::TBindTo>(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<const CTunDriverProtoProvision*>(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());
+        }
+    }
+