|
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 |