linklayerprotocols/tundriver/src/tundriverflow.cpp
branchRCL_3
changeset 23 425d8f4f7fa5
equal deleted inserted replaced
22:8d540f55e491 23:425d8f4f7fa5
       
     1 /**
       
     2 *   Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 *   All rights reserved.
       
     4 *   This component and the accompanying materials are made available
       
     5 *   under the terms of "Eclipse Public License v1.0"
       
     6 *   which accompanies this distribution, and is available
       
     7 *   at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *   
       
     9 *   Initial Contributors:
       
    10 *   Nokia Corporation - initial contribution.
       
    11 *   
       
    12 *   Contributors:
       
    13 *
       
    14 *   Description:
       
    15 *   Flow implementation for data path for tunnel driver.
       
    16 * 
       
    17 *
       
    18 */
       
    19 
       
    20 /**
       
    21  @file tundriverflow.cpp
       
    22  @internalTechnology
       
    23 */
       
    24 
       
    25 #include <e32std.h>
       
    26 #include <ecom/ecom.h>
       
    27 #include <ecom/implementationproxy.h>
       
    28 #include <elements/nm_messages_base.h>
       
    29 #include <elements/nm_messages_child.h>
       
    30 
       
    31 #include "ss_subconnflow.h"
       
    32 #include <comms-infras/ss_log.h>
       
    33 #include "tundriverflow.h"
       
    34 #include "tundriverbinder.h"
       
    35 #include "tundriverprovision.h"
       
    36 
       
    37 using namespace Messages;
       
    38 using namespace MeshMachine;
       
    39 using namespace ESock;
       
    40 
       
    41 #ifdef SYMBIAN_TRACE_ENABLE
       
    42 _LIT8(KNif,"tundriver");
       
    43 #endif
       
    44 
       
    45 CTunDriverSubConnectionFlowFactory* CTunDriverSubConnectionFlowFactory::NewL(TAny* aConstructionParameters)
       
    46 /**
       
    47 * CTunDriverSubConnectionFlowFactory::NewL constructs a Default SubConnection Flow Factory
       
    48 * @param aConstructionParameters construction data passed by ECOM
       
    49 * @returns pointer to a constructed factory object.
       
    50 */
       
    51     {
       
    52     CTunDriverSubConnectionFlowFactory* ptr = new (ELeave) CTunDriverSubConnectionFlowFactory(TUid::Uid(KTunDriverFlowImplementationUid), *(reinterpret_cast<CSubConnectionFlowFactoryContainer*>(aConstructionParameters)));
       
    53     return ptr;
       
    54     }
       
    55 
       
    56 
       
    57 CTunDriverSubConnectionFlowFactory::CTunDriverSubConnectionFlowFactory(TUid aFactoryId, CSubConnectionFlowFactoryContainer& aParentContainer)
       
    58 :   CSubConnectionFlowFactoryBase(aFactoryId, aParentContainer)
       
    59 /**
       
    60 * CTunDriverSubConnectionFlowFactory::CTunDriverSubConnectionFlowFactory is a Default SubConnection Flow Factory
       
    61 * @param aFactoryId ECOM Implementation Id
       
    62 * @param aParentContainer Object Owner
       
    63 */
       
    64     {
       
    65     }
       
    66 
       
    67 CSubConnectionFlowBase* CTunDriverSubConnectionFlowFactory::DoCreateFlowL(CProtocolIntfBase* aProtocolIntf, TFactoryQueryBase& aQuery)
       
    68 /**
       
    69 * CTunDriverSubConnectionFlowFactory::DoCreateFlowL will create SubConnection Flow.
       
    70 * @param aFactoryId ECOM Implementation Id
       
    71 * @param aParentContainer Object Owner
       
    72 */
       
    73     {
       
    74     const TDefaultFlowFactoryQuery& query = static_cast<const TDefaultFlowFactoryQuery&>(aQuery);
       
    75     return CTunDriverSubConnectionFlow::NewL(*this, query.iSCprId, aProtocolIntf);
       
    76     }
       
    77 
       
    78 CTunDriverSubConnectionFlow::CTunDriverSubConnectionFlow(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
       
    79 :   CSubConnectionFlowBase(aFactory, aSubConnId, aProtocolIntf)
       
    80 /**
       
    81 * CTunDriverSubConnectionFlow::CTunDriverSubConnectionFlow is a Default Constructor
       
    82 * @param aFactoryId ECOM Implementation Id
       
    83 * @param aParentContainer Object Owner
       
    84 */
       
    85     {
       
    86     __FLOG_OPEN(KCFNodeTag, KNif);
       
    87     LOG_NODE_CREATE(KNif, CTunDriverSubConnectionFlow);
       
    88     }
       
    89 
       
    90 CTunDriverSubConnectionFlow::~CTunDriverSubConnectionFlow()
       
    91 /**
       
    92 * CTunDriverSubConnectionFlowFactory::~CTunDriverSubConnectionFlow is a Default destructor
       
    93 * @param aFactoryId ECOM Implementation Id
       
    94 * @param aParentContainer Object Owner
       
    95 */
       
    96     {
       
    97     delete iBinder4;
       
    98     iBinder4 = NULL;
       
    99 #ifdef IPV6SUPPORT
       
   100     delete iBinder6;
       
   101     iBinder6 = NULL;
       
   102 #endif
       
   103     LOG_NODE_DESTROY(KNif, CTunDriverSubConnectionFlow);
       
   104     __FLOG_CLOSE;
       
   105     }
       
   106 
       
   107 CTunDriverSubConnectionFlow* CTunDriverSubConnectionFlow::NewL(CSubConnectionFlowFactoryBase& aFactory, const TNodeId& aSubConnId, CProtocolIntfBase* aProtocolIntf)
       
   108 /**
       
   109 * CTunDriverSubConnectionFlowFactory::NewL is a first phase Constructor.
       
   110 * @param aFactoryId ECOM Implementation Id
       
   111 * @param aParentContainer Object Owner
       
   112 */
       
   113     {
       
   114     CTunDriverSubConnectionFlow* flow = new (ELeave) CTunDriverSubConnectionFlow(aFactory, aSubConnId, aProtocolIntf);
       
   115     return flow;
       
   116     }
       
   117 
       
   118 void CTunDriverSubConnectionFlow::FlowDown(TInt aError, TInt aAction /*= MNifIfNotify::EDisconnect*/)
       
   119 /**
       
   120 * CTunDriverSubConnectionFlowFactory::FlowDown will post the message.
       
   121 * @param aError obtained from the upper CF Layer.
       
   122 * @param aAction and the action message for aError.
       
   123 */
       
   124     {
       
   125     PostFlowDownMessage(aError, aAction);
       
   126     }
       
   127 
       
   128 void CTunDriverSubConnectionFlow::Progress(TInt aStage, TInt aError)
       
   129 /**
       
   130 * CTunDriverSubConnectionFlowFactory::Progress Binder requesting a Progress() message be sent to SCPR
       
   131 * @param aStage and the action message for aError.
       
   132 * @param aError obtained from the upper CF Layer.
       
   133 */
       
   134     {
       
   135     PostProgressMessage(aStage, aError);
       
   136     }
       
   137 
       
   138 const TTunDriverIp4Provision* CTunDriverSubConnectionFlow::Ip4Provision() const
       
   139 /**
       
   140 * CTunDriverSubConnectionFlowFactory::Ip4Provision
       
   141 * @param 
       
   142 * @return iIp4Provision.
       
   143 */
       
   144     {
       
   145     ASSERT(iProvision);
       
   146     return &iProvision->iIp4Provision;
       
   147     }
       
   148 
       
   149 #ifdef IPV6SUPPORT
       
   150 const TTunDriverIp6Provision* CTunDriverSubConnectionFlow::Ip6Provision() const
       
   151 /**
       
   152 * CTunDriverSubConnectionFlowFactory::Ip6Provision
       
   153 * @param 
       
   154 * @return iIp6Provision.
       
   155 */
       
   156     {
       
   157     ASSERT(iProvision);
       
   158     return &iProvision->iIp6Provision;
       
   159     }
       
   160 #endif
       
   161 
       
   162 //-=========================================================
       
   163 // Messages::ANode methods
       
   164 //-=========================================================
       
   165 
       
   166 #define __FRAMEWORK_PRODUCTION_ERRORHANDLING(c,p) (void)((c)||(p,0))
       
   167 void CTunDriverSubConnectionFlow::ReceivedL(const TRuntimeCtxId& aSender, const TNodeId& aRecipient, TSignatureBase& aMessage)
       
   168 /**
       
   169 * CTunDriverSubConnectionFlowFactory::ReceivedL called on incoming SCPR Messages.
       
   170 * CTunDriverSubConnectionFlow functions will be called Based on message type
       
   171 * @param aCFMessage message base
       
   172 */
       
   173     {
       
   174     #ifdef __FLOG_ACTIVE
       
   175         TAny* senderAddr = NULL;
       
   176         const TNodeId* senderNodeId = address_cast<TNodeId>(&aSender);
       
   177         __ASSERT_DEBUG(senderNodeId!=NULL,User::LeaveIfError(KErrCorrupt));
       
   178         senderAddr = senderNodeId->Ptr();
       
   179         __FLOG_4(_L8("CTunDriverSubConnectionFlow(%x):\tReceivedL() Sender Id: %x, Msg Realm: %X, Msg ID: %d"), this, senderAddr, aMessage.MessageId().Realm(), aMessage.MessageId().MessageId());
       
   180     #endif
       
   181 
       
   182     CSubConnectionFlowBase::ReceivedL(aSender, aRecipient, aMessage);
       
   183     if (aMessage.IsMessage<TEBase::TError>())
       
   184         {
       
   185         SubConnectionError(static_cast<TEBase::TError&>(aMessage).iValue);
       
   186         }
       
   187     else if (TEChild::ERealmId == aMessage.MessageId().Realm())
       
   188         {
       
   189         switch (aMessage.MessageId().MessageId())
       
   190             {
       
   191         case TEChild::TCancel::EId:
       
   192             CancelFlow(KErrCancel);
       
   193         case TEChild::TDestroy::EId :
       
   194             Destroy();
       
   195             break;
       
   196         default:
       
   197             ASSERT(EFalse);
       
   198             }
       
   199         }
       
   200     else if (TCFDataClient::ERealmId == aMessage.MessageId().Realm())
       
   201         {
       
   202         switch (aMessage.MessageId().MessageId())
       
   203             {
       
   204         case TCFDataClient::TStart::EId :
       
   205             StartFlowL();
       
   206             break;
       
   207         case TCFDataClient::TStop::EId :
       
   208             StopFlow(static_cast<TCFDataClient::TStop&>(aMessage).iValue);
       
   209             break;
       
   210         case TCFDataClient::TProvisionConfig::EId:
       
   211             ProvisionConfig(static_cast<TCFDataClient::TProvisionConfig&>(aMessage).iConfig);
       
   212             break;
       
   213         case TCFDataClient::TBindTo::EId:
       
   214             {
       
   215             TCFDataClient::TBindTo& bindToReq = message_cast<TCFDataClient::TBindTo>(aMessage);
       
   216             __FRAMEWORK_PRODUCTION_ERRORHANDLING(bindToReq.iNodeId.IsNull(),User::LeaveIfError(KErrNotSupported));
       
   217             RClientInterface::OpenPostMessageClose(Id(), aSender, TCFDataClient::TBindToComplete().CRef());
       
   218             }
       
   219             break;
       
   220         default:
       
   221             ASSERT(EFalse);
       
   222             }
       
   223         }
       
   224     else
       
   225         {
       
   226         User::Leave(KErrNotSupported);
       
   227         }
       
   228     }
       
   229 
       
   230 void CTunDriverSubConnectionFlow::StartFlowL()
       
   231 /**
       
   232 * CTunDriverSubConnectionFlowFactory::StartFlowL starts the flow on receiving the message TStart.
       
   233 * This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
       
   234 */
       
   235     {
       
   236     __FLOG(_L8("CTunDriverSubConnectionFlow:\tStartFlowL()"));
       
   237     
       
   238     if(iMMState == EStarted)
       
   239         {
       
   240         //Flow can be started multiple times.
       
   241         //For example a start may fail on an upper layer in which case the upper layer will not be able
       
   242         //to stop our layer and we need to accept start again.
       
   243         PostProgressMessage(KLinkLayerOpen, KErrNone);
       
   244         PostDataClientStartedMessage();
       
   245         return;
       
   246         }
       
   247     iMMState = EStarted;
       
   248 
       
   249     // If the processing of the ProvisionConfig message failed earlier, send the error response
       
   250     // here to the StartFlow message as there is no response to ProvisionConfig.
       
   251     User::LeaveIfError(iSavedError);
       
   252 
       
   253     PostProgressMessage(KLinkLayerOpen, KErrNone);
       
   254     PostDataClientStartedMessage();
       
   255     iBinder4->StartSending();
       
   256 #ifdef IPV6SUPPORT
       
   257     if(iBinder6)
       
   258         {
       
   259         iBinder6->StartSending();
       
   260         }
       
   261 #endif
       
   262     }
       
   263 
       
   264 void CTunDriverSubConnectionFlow::CancelFlow(TInt aError)
       
   265 /**
       
   266 * CTunDriverSubConnectionFlowFactory::CancelFlow cancels the flow on receiving the message TCancel.
       
   267 * It will post the message as KErrCancel.
       
   268 * This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
       
   269 */
       
   270     {
       
   271     __FLOG_1(_L8("CTunDriverSubConnectionFlow:\tCancelFlow(%d)"), aError);
       
   272 
       
   273     if(iMMState == EStarted)
       
   274         {
       
   275         PostFlowDownMessage(aError);
       
   276         }
       
   277     }
       
   278 
       
   279 void CTunDriverSubConnectionFlow::StopFlow(TInt aError)
       
   280 /**
       
   281 * CTunDriverSubConnectionFlowFactory::StopFlow stops the flow on receiving the message TStop.
       
   282 * It will post the message as KLinkLayerClosed and KErrCancel.
       
   283 * This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
       
   284 */
       
   285     {
       
   286     __FLOG_1(_L8("CTunDriverSubConnectionFlow:\tStopFlow(%d)"), aError);
       
   287 
       
   288     PostProgressMessage(KLinkLayerClosed, aError);
       
   289     iMMState = EStopped;
       
   290     PostFlowDownMessage(aError);
       
   291     }
       
   292 
       
   293 void CTunDriverSubConnectionFlow::ProvisionConfig(const ESock::RMetaExtensionContainerC& aConfigData)
       
   294 /**
       
   295 * CTunDriverSubConnectionFlowFactory::Provisionconfig on receipt of the ProvisionConfig message, the pointer contained within it is stored
       
   296 * in iAccessPointConfig and the information contained within the iAccessPointConfig  array is validated:
       
   297 * CTunDriverProtoProvision must be present.  It is added by the TunDriverMCPr and populated from CommsDat.
       
   298 * It is a 'C' class to take advantage of zero initialisation.
       
   299 * Any errors are saved in iSavedError - there is no response to ProvisionConfig, 
       
   300 * so an error response is sent later to StartFlow message.
       
   301 *
       
   302 * on receipt of TCFDataClient::TStart:
       
   303 * iSavedError is checked and, if non-zero, an Error message is sent to the SCPr
       
   304 * TunDriverAgentProvision must be present.  It is added by the TunDriverAgentHandler and populated via calls
       
   305 * to the Agent.  It is a 'T' class because it requires no zero initialisation.  If missing,
       
   306 * an Error message is signalled to the SCPr.
       
   307 * This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL
       
   308 * @param aData pointer to provisioning structure 
       
   309 */
       
   310     {
       
   311     __FLOG_0(_L8("CTunDriverSubConnectionFlow:\tProvisionConfig message received"));
       
   312     iSavedError = KErrNone;
       
   313     iAccessPointConfig.Close();
       
   314     iAccessPointConfig.Open(aConfigData);
       
   315 
       
   316     const CTunDriverProtoProvision* provision = static_cast<const CTunDriverProtoProvision*>(AccessPointConfig().FindExtension(
       
   317             STypeId::CreateSTypeId(CTunDriverProtoProvision::EUid, CTunDriverProtoProvision::ETypeId)));
       
   318     __FRAMEWORK_PRODUCTION_ERRORHANDLING(provision!=NULL,iSavedError = KErrCorrupt);
       
   319     
       
   320     iProvision = provision;
       
   321     }
       
   322 
       
   323 void CTunDriverSubConnectionFlow::Destroy()
       
   324 /**
       
   325 * CTunDriverSubConnectionFlowFactory::Destroy
       
   326 * Request from SCPR to destroy
       
   327 * This function is called from CTunDriverSubConnectionFlowFactory::ReceivedL 
       
   328 */
       
   329     {
       
   330     DeleteThisFlow();
       
   331     }
       
   332 
       
   333 void CTunDriverSubConnectionFlow::SubConnectionGoingDown()
       
   334 /**
       
   335 * CTunDriverSubConnectionFlowFactory::SubConnectionGoingDown
       
   336 * Request from Agemt SCPR
       
   337 */
       
   338     {
       
   339     __FLOG(_L8("CTunDriverSubConnectionFlow:\tSubConnectionGoingDown"));
       
   340     }
       
   341 
       
   342 void CTunDriverSubConnectionFlow::SubConnectionError(TInt /*aError*/)
       
   343 /**
       
   344 * CTunDriverSubConnectionFlowFactory::SubConnectionError
       
   345 * Request from Agemt SCPR
       
   346 */
       
   347     {
       
   348     __FLOG(_L8("CTunDriverSubConnectionFlow:\tSubConnectionError"));
       
   349     }
       
   350 
       
   351 MFlowBinderControl* CTunDriverSubConnectionFlow::DoGetBinderControlL()
       
   352 /**
       
   353 * CTunDriverSubConnectionFlowFactory::DoGetBinderControlL Called by upper layer for binding
       
   354 * Request from Agemt SCPR
       
   355 * @return MFlowBinderControl instance
       
   356 */
       
   357     {
       
   358     __FLOG(_L8("CTunDriverSubConnectionFlow::DoGetBinderControlL"));
       
   359     return this;
       
   360     }
       
   361 
       
   362 //-=========================================================
       
   363 // MFlowBinderControl methods
       
   364 //
       
   365 
       
   366 MLowerControl* CTunDriverSubConnectionFlow::GetControlL(const TDesC8& aProtocol)
       
   367 /**
       
   368 * CTunDriverSubConnectionFlow::GetControlL
       
   369 * Create and return an MLowerControl instance of the specified binder type.
       
   370 * Called from upper layer during binding procedure.
       
   371 * @param aProtocol Protocol type of the binder
       
   372 * @return MLowerControl instance of the protocol type
       
   373 */
       
   374     {
       
   375     MLowerControl* lowerControl = NULL;
       
   376     __FLOG(_L8("CTunDriverSubConnectionFlow:\tGetLowerControlL(KProtocol4)"));
       
   377     if(aProtocol.Compare(KProtocol4()) == 0)
       
   378     		{
       
   379     		iBinder4 = CTunDriverBinder4::NewL(*this);
       
   380     		lowerControl = iBinder4;
       
   381     		}
       
   382 #ifdef IPV6SUPPORT
       
   383     else
       
   384     if (aProtocol.CompareF(KProtocol6()) == 0)
       
   385         {
       
   386         __FLOG(_L8("CTunDriverSubConnectionFlow::GetLowerControlL(KProtocol6)- Should Return KErrNotSupported"));
       
   387         iBinder6 = CTunDriverBinder6::NewL(*this);
       
   388         lowerControl = iBinder6;        
       
   389         }
       
   390 #endif
       
   391     return lowerControl;
       
   392     }
       
   393 
       
   394 MLowerDataSender* CTunDriverSubConnectionFlow::BindL(const TDesC8& aProtocol, MUpperDataReceiver* aReceiver, MUpperControl* aControl)
       
   395 /**
       
   396 * CTunDriverSubConnectionFlow::BindL Create and return an MLowerDataSender instance of the specified protocol type.
       
   397 * This is bound to the specified upper layer objects.
       
   398 * Called from upper layer to bind to this layer.
       
   399 * @param aProtocol Protocol type of the binder (same as in GetControlL())
       
   400 * @param aReceiver upper layer's MUpperDataReceiver instance for this binder to associate with
       
   401 * @param aControl upper layer's MUpperControl instance for this binder to associate with
       
   402 * @return MLowerDataSender instance
       
   403 */
       
   404     {
       
   405     __FLOG(_L8("CTunDriverSubConnectionFlow:\tBindL()"));
       
   406 
       
   407     MLowerDataSender* lowerDataSender = NULL;
       
   408 
       
   409     if(aProtocol.CompareF(KProtocol4()) == 0)
       
   410     		{
       
   411     		lowerDataSender = iBinder4->Bind(*aReceiver, *aControl);
       
   412     		}
       
   413 #ifdef IPV6SUPPORT
       
   414     else
       
   415     if (aProtocol.CompareF(KProtocol6()) == 0)
       
   416         {
       
   417         lowerDataSender = iBinder6->Bind(*aReceiver, *aControl);
       
   418         }
       
   419 #endif
       
   420     if(lowerDataSender != NULL)
       
   421         {
       
   422         iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TActive().CRef());
       
   423         }
       
   424     return lowerDataSender;
       
   425     }
       
   426 
       
   427 void CTunDriverSubConnectionFlow::Unbind(MUpperDataReceiver* aReceiver, MUpperControl* aControl)
       
   428 /**
       
   429 * CTunDriverSubConnectionFlow::Unbind will Unbind from the upper layer.
       
   430 * Called from the upper layer during unbinding.
       
   431 * @param aReceiver
       
   432 * @param aControl
       
   433 */
       
   434     {
       
   435     __FLOG(_L8("CTunDriverSubConnectionFlow:\tUnbind()"));
       
   436     if (iBinder4 && iBinder4->MatchesUpperControl(aControl))
       
   437             {
       
   438             iBinder4->Unbind(*aReceiver, *aControl);
       
   439             delete iBinder4;
       
   440             iBinder4 = NULL;
       
   441             }
       
   442 #ifdef IPV6SUPPORT
       
   443     if (iBinder6 && iBinder6->MatchesUpperControl(aControl))
       
   444             {
       
   445             iBinder6->Unbind(*aReceiver, *aControl);
       
   446             delete iBinder6;
       
   447             iBinder6 = NULL;
       
   448             }
       
   449 #endif
       
   450     iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
       
   451     }
       
   452 
       
   453 ESock::CSubConnectionFlowBase* CTunDriverSubConnectionFlow::Flow()
       
   454 /**
       
   455 * CTunDriverSubConnectionFlow::Flow will Return the flow object corresponding to the MFlowBinderControl
       
   456 * Called from the UpperLayer get the instance of the flow.
       
   457 */
       
   458     {
       
   459     return this;
       
   460     }
       
   461 
       
   462 void CTunDriverSubConnectionFlow::PostProgressMessage(TInt aStage, TInt aError)
       
   463 /*
       
   464 * CTunDriverSubConnectionFlow::PostProgressMessage will send the state change message with the param values.
       
   465 * 
       
   466 */
       
   467     {
       
   468     iSubConnectionProvider.PostMessage(Id(), TCFMessage::TStateChange(Elements::TStateChange(aStage, aError)).CRef());
       
   469     }
       
   470 
       
   471 void CTunDriverSubConnectionFlow::PostDataClientStartedMessage()
       
   472 /*
       
   473 * CTunDriverSubConnectionFlow::PostDataClientStartedMessage will send the started message with the param values.
       
   474 */
       
   475     {
       
   476     iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStarted().CRef());
       
   477     }
       
   478 
       
   479 void CTunDriverSubConnectionFlow::PostFlowDownMessage(TInt aError, TInt aAction /*= MNifIfNotify::EDisconnect*/)
       
   480 /*
       
   481 * CTunDriverSubConnectionFlow::PostFlowDownMessage will send the DataClient Down message with the param values.
       
   482 */
       
   483     {
       
   484     if (iMMState == EStarted)
       
   485         {
       
   486         iMMState = EStopped;
       
   487         iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TDataClientGoneDown(aError, aAction).CRef());
       
   488         }
       
   489     else
       
   490         {
       
   491         iLastRequestOriginator.ReplyTo(Id(), TCFDataClient::TStopped(aError).CRef());
       
   492         }
       
   493     }
       
   494 
       
   495 void CTunDriverSubConnectionFlow::MaybePostDataClientIdle()
       
   496 /*
       
   497 * CTunDriverSubConnectionFlow::MaybePostDataClientIdle will send the Idle message with the param values.
       
   498 */
       
   499     {
       
   500     // Can only send DataClientIdle when the upper layer has unbound and the flow is stopped
       
   501     if( iBinder4 == NULL
       
   502 #ifdef IPV6SUPPORT
       
   503         || iBinder6 == NULL
       
   504 #endif
       
   505       )
       
   506         {
       
   507         iSubConnectionProvider.PostMessage(Id(), TCFControlProvider::TIdle().CRef());
       
   508         }
       
   509     }
       
   510