|
1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // CNifIfBase and CProtocolBase shim layer functionality |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file nif.cpp |
|
20 */ |
|
21 |
|
22 #include <e32base.h> |
|
23 #include <networking/qos_if.h> |
|
24 #include <nifmbuf.h> |
|
25 #include <es_prot_internal.h> |
|
26 #include <comms-infras/ss_subconnflow.h> |
|
27 #include <comms-infras/ss_protflow.h> |
|
28 |
|
29 #include "in_sock.h" |
|
30 #include "in_iface.h" |
|
31 #include "in6_if.h" |
|
32 |
|
33 #include "flow.h" |
|
34 #include "nif.h" |
|
35 #include "notify.h" |
|
36 #include "panic.h" |
|
37 #include "ItfInfoConfigExt.h" |
|
38 |
|
39 #include "nif4.h" // for CIPShimIfBase::NewL() |
|
40 #include "nif6.h" // for CIPShimIfBase::NewL() |
|
41 |
|
42 #include "IPProtoDeMux.h" |
|
43 |
|
44 #include "../addressinfohook/inc/hookaddrinfo.h" |
|
45 |
|
46 |
|
47 using namespace ESock; |
|
48 |
|
49 // |
|
50 // CIPShimIfBase methods |
|
51 // |
|
52 |
|
53 CIPShimIfBase* CIPShimIfBase::NewL(const TDesC8& aProtocol, CIPShimProtocolIntf *aIntf) |
|
54 { |
|
55 CIPShimIfBase* intf = NULL; |
|
56 |
|
57 if (aProtocol.CompareF(KProtocolIp()) == 0) |
|
58 { |
|
59 intf = CIPShimIfBase4::NewL(aProtocol); |
|
60 } |
|
61 else |
|
62 if (aProtocol.CompareF(KProtocolIp6()) == 0) |
|
63 { |
|
64 intf = CIPShimIfBase6::NewL(aProtocol); |
|
65 } |
|
66 else |
|
67 { |
|
68 // only support "ip" and "ip6" protocol names |
|
69 User::Leave(KErrArgument); |
|
70 } |
|
71 intf->SetProtocolIntf(aIntf); |
|
72 |
|
73 return intf; |
|
74 } |
|
75 |
|
76 |
|
77 CIPShimIfBase::CIPShimIfBase(const TDesC8& aProtocolName) |
|
78 : CNifIfBase(), iBinderReady(EFalse), iProtIntf(NULL) |
|
79 /** |
|
80 CIPShimIfBase constructor |
|
81 */ |
|
82 { |
|
83 __CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L8("CIPShimIfBase %08x:\tCIPShimIfBase(aProtocolName '%S')"), this, &aProtocolName); |
|
84 iProtocolName.Copy(aProtocolName); |
|
85 } |
|
86 |
|
87 CIPShimIfBase::~CIPShimIfBase() |
|
88 { |
|
89 __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\t~CIPShimIfBase()"), this); |
|
90 delete iShimNotify; |
|
91 |
|
92 for (TInt i = 0; i < iProtoBinders.Count(); i++) |
|
93 { |
|
94 iProtoBinders[i]->Unbind(); |
|
95 } |
|
96 |
|
97 iProtoBinders.Close(); |
|
98 |
|
99 /* ASSERT(iProtIntf); |
|
100 iProtIntf->NifDisappearing(this);*/ |
|
101 |
|
102 /* |
|
103 * it's not legal to assume that this pointer isn't NULL. There can be |
|
104 * OOM conditions in the constructor (which doesn't follow the official |
|
105 * 2 way constructions [in nif4 or nif6]) which can cause not to initialize |
|
106 * this pointer. |
|
107 */ |
|
108 if (iProtIntf) |
|
109 { |
|
110 iProtIntf->NifDisappearing(this); |
|
111 } |
|
112 } |
|
113 |
|
114 void CIPShimIfBase::ConstructL() |
|
115 { |
|
116 iShimNotify = CIPShimNotify::NewL(this); |
|
117 // Setup the CNifIfBase::iNotify for the benefit of the TCP/IP stack to call us |
|
118 iNotify = static_cast<MNifIfNotify*>(iShimNotify); |
|
119 } |
|
120 |
|
121 void CIPShimIfBase::StartL() |
|
122 { |
|
123 if (iUpperProtocol) |
|
124 { |
|
125 return; |
|
126 } |
|
127 |
|
128 TBuf<KMaxProtocolNameSize> protocolName; |
|
129 protocolName.Copy(iProtocolName); |
|
130 __CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartL(): FindAndLoadProtocolL('%S')"), this, &protocolName); |
|
131 iUpperProtocol = SocketServExt::FindAndLoadProtocolL(protocolName); |
|
132 iUpperProtocol->Open(); |
|
133 |
|
134 |
|
135 // Retrieve the MNifIfUser derived object from the upper protocol |
|
136 |
|
137 TNifIfUser ifuser; |
|
138 TInt err = iUpperProtocol->GetOption(KNifOptLevel, KNifOptGetNifIfUser, ifuser, 0); |
|
139 |
|
140 if (err == KErrNone) |
|
141 { |
|
142 iNifUser = ifuser(); |
|
143 |
|
144 // Inform the upper protocol of our CNifIfBase derived interface. |
|
145 // (the second argument does not appear to be used in current SymbianOS, so pass 0). |
|
146 __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartL(): IfUserNewInterfaceL()"), this); |
|
147 |
|
148 CleanupClosePushL(*iUpperProtocol); |
|
149 iNifUser->IfUserNewInterfaceL(this, 0); // Note: increments CNifIfBase reference |
|
150 CleanupStack::Pop(); |
|
151 |
|
152 // Cleanup Note: if you ever add a leaving function after IfUserNewInterfaceL() above, |
|
153 // then you'll need to arrange for CleanupSignalNewInterface() to be called here (it is pushed |
|
154 // onto the cleanup stack later as there are no subsequent leaving functions in this routine. |
|
155 |
|
156 iNifUser->IfUserOpenNetworkLayer(); // Note: increments protocol reference count |
|
157 } |
|
158 else |
|
159 { |
|
160 __CFLOG_VAR((KIPProtoTag1, KIPProtoTag2, _L8("CIPShimIfBase %08x:\tStartL(): Error %d issuing KNifOptGetNifIfUser to protocol"), this, err)); |
|
161 User::Leave(err); |
|
162 } |
|
163 } |
|
164 |
|
165 void CIPShimIfBase::BindToL(CIPProtoBinder* aIPProtoBinder) |
|
166 { |
|
167 aIPProtoBinder->BindL(this); |
|
168 iProtoBinders.AppendL(aIPProtoBinder); |
|
169 } |
|
170 |
|
171 void CIPShimIfBase::UnbindFrom(CIPProtoBinder* aIPProtoBinder) |
|
172 { |
|
173 TInt index = iProtoBinders.Find(aIPProtoBinder); |
|
174 |
|
175 // shouldn't try to unbind from a binder we're not bound to |
|
176 ASSERT(index >= 0); |
|
177 iProtoBinders.Remove(index); |
|
178 aIPProtoBinder->Unbind(); |
|
179 } |
|
180 |
|
181 //-========================================= |
|
182 // MUpperDataReceiver methods |
|
183 //-========================================= |
|
184 void CIPShimIfBase::Process(RMBufChain& aData) |
|
185 { |
|
186 iUpperProtocol->Process(aData, reinterpret_cast<CProtocolBase*>(this)); |
|
187 } |
|
188 |
|
189 //-========================================= |
|
190 // MUpperControl methods |
|
191 //-========================================= |
|
192 void CIPShimIfBase::StartSending() |
|
193 { |
|
194 if (!iBinderReady) |
|
195 { |
|
196 // Get config info (for first time) |
|
197 __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartSending() (first time)"), this); |
|
198 GetConfigFirstTime(); |
|
199 iBinderReady = ETrue; |
|
200 } |
|
201 |
|
202 if (iUpperProtocol) |
|
203 { |
|
204 // Call StartSending(...) in the context of "downstream path ready for first time" |
|
205 __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tStartSending()"), this); |
|
206 iUpperProtocol->StartSending(reinterpret_cast<CProtocolBase*>(this)); |
|
207 } |
|
208 } |
|
209 |
|
210 void CIPShimIfBase::Error(TInt anError) |
|
211 { |
|
212 iProtoBinders[0]->Error(anError); |
|
213 } |
|
214 |
|
215 #ifdef _DEBUG |
|
216 void CIPShimIfBase::BindL(TAny* aId) |
|
217 #else |
|
218 void CIPShimIfBase::BindL(TAny* /*aId*/) |
|
219 #endif |
|
220 /** |
|
221 Called from upper protocol to pass its CProtocolBase pointer |
|
222 */ |
|
223 { |
|
224 //[401TODO] RZ: Is this assumption safe? |
|
225 ASSERT(iUpperProtocol == aId); |
|
226 |
|
227 if (iBinderReady && iUpperProtocol) |
|
228 { |
|
229 __CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tBindL(%08x)"), this, aId); |
|
230 iUpperProtocol->StartSending(reinterpret_cast<CProtocolBase*>(this)); |
|
231 } |
|
232 } |
|
233 |
|
234 void CIPShimIfBase::CleanupInterface(TInt aError) |
|
235 { |
|
236 __CFLOG_2(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %x:\tCleanupInterface(%d)"), this, aError); |
|
237 iUpperProtocol->Close(); |
|
238 iUpperProtocol = NULL; |
|
239 |
|
240 if(iInterfaceNameRecorded && iProtoBinders.Count()) |
|
241 { |
|
242 XInterfaceNames* itfNames = static_cast<XInterfaceNames*>( |
|
243 const_cast<Meta::SMetaData*>(iProtoBinders[0]->Flow().AccessPointConfig().FindExtension(XInterfaceNames::TypeId()))); |
|
244 itfNames->RemoveInterfaceName(this); |
|
245 } |
|
246 |
|
247 // IfUserInterfaceDown may delete this object, so create a stack variable for the NifIfUser |
|
248 // so CloseNetworkLayer can be called on it. |
|
249 MNifIfUser* nifUser = iNifUser; |
|
250 nifUser->IfUserInterfaceDown(aError, this); // Note: decrements CNifIfBase reference |
|
251 nifUser->IfUserCloseNetworkLayer(); // Note: decrements protocol reference count |
|
252 } |
|
253 |
|
254 void CIPShimIfBase::RemoveInterfaceName(CIPProtoBinder* aBinder) |
|
255 { |
|
256 ASSERT(aBinder); |
|
257 |
|
258 if(iInterfaceNameRecorded) |
|
259 { |
|
260 XInterfaceNames* itfNames = static_cast<XInterfaceNames*>( |
|
261 const_cast<Meta::SMetaData*>(aBinder->Flow().AccessPointConfig().FindExtension(XInterfaceNames::TypeId()))); |
|
262 itfNames->RemoveInterfaceName(this); |
|
263 } |
|
264 } |
|
265 |
|
266 |
|
267 void CIPShimIfBase::Release(TInt aError) |
|
268 { |
|
269 /* CleanupInterface will delete the interface when it is done if refcount is 0 (it will decrement it itself). |
|
270 If iRefCount 0 when release is called, Start must never have been |
|
271 called on this nif. */ |
|
272 if (iProtoBinders.Count()) |
|
273 { |
|
274 return; //can't go away if we still have binders |
|
275 } |
|
276 |
|
277 if (iRefCount == 0) |
|
278 { |
|
279 delete this; |
|
280 } |
|
281 else |
|
282 { |
|
283 CleanupInterface(aError); |
|
284 } |
|
285 } |
|
286 |
|
287 TInt CIPShimIfBase::State() |
|
288 { |
|
289 return EIfDown; |
|
290 } |
|
291 |
|
292 TInt CIPShimIfBase::ServiceHwAddrControl(TDes8& aOption) |
|
293 /** |
|
294 Service KSoIfHardwareAddr calls from upper protocol |
|
295 */ |
|
296 { |
|
297 ASSERT(aOption.Length() == sizeof(TSoIfHardwareAddr)); |
|
298 if (iProtoBinders.Count()) |
|
299 { |
|
300 //[401TODO] RZ: we're probably need fixed array to avoid index changing |
|
301 return iProtoBinders[0]->Control(KSOLInterface, KSoIfHardwareAddr, aOption); |
|
302 } |
|
303 else |
|
304 { |
|
305 __CFLOG_1(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tServiceHwAddrControl(): no binders"), this); |
|
306 return KErrNotReady; |
|
307 } |
|
308 } |
|
309 |
|
310 TInt CIPShimIfBase::ServiceConnInfo(TDes8& aOption) |
|
311 /** |
|
312 Service KSoIfGetConnectionInfo calls from upper protocol |
|
313 */ |
|
314 { |
|
315 ASSERT(aOption.Length() == sizeof(TSoIfConnectionInfo)); |
|
316 TUint8* ptr = const_cast<TUint8*>(aOption.Ptr()); |
|
317 TSoIfConnectionInfo& returnedInfo = reinterpret_cast<TSoIfConnectionInfo&>(*ptr); |
|
318 |
|
319 returnedInfo.iIAPId = iConnectionInfo.iIapId; |
|
320 returnedInfo.iNetworkId = iConnectionInfo.iNetId; |
|
321 |
|
322 return KErrNone; |
|
323 } |
|
324 |
|
325 TInt CIPShimIfBase::Control(TUint aLevel, TUint aName, TDes8& aOption, TAny* aSource) |
|
326 { |
|
327 __CFLOG_3(KIPProtoTag1, KIPProtoTag2, _L("CIPShimIfBase %08x:\tControl(aLevel 0x%x, aName 0x%x)"), this, aLevel, aName); |
|
328 if (aLevel == KSOLInterface) |
|
329 { |
|
330 switch (aName) |
|
331 { |
|
332 case KSoIfInfo: |
|
333 /* FALLTHROUGH */ |
|
334 case KSoIfInfo6: |
|
335 return ServiceInfoControl(aOption, aName); |
|
336 |
|
337 case KSoIfConfig: |
|
338 return ServiceConfigControl(aOption); |
|
339 |
|
340 case KSoIfHardwareAddr: |
|
341 return ServiceHwAddrControl(aOption); |
|
342 |
|
343 case KSoIfGetConnectionInfo: |
|
344 return ServiceConnInfo(aOption); |
|
345 case 0x734: |
|
346 iHookAddressInfo = (CHookAddressInfo*)aSource; |
|
347 return KErrNone; |
|
348 default: |
|
349 break; |
|
350 } |
|
351 } |
|
352 |
|
353 if (iProtoBinders.Count()) |
|
354 { |
|
355 //[401TODO] RZ: we're probably need fixed array to avoid index changing |
|
356 return iProtoBinders[0]->Control(aLevel, aName, aOption); |
|
357 } |
|
358 return KErrNotReady; |
|
359 } |
|
360 |
|
361 void CIPShimIfBase::Info(TNifIfInfo& aInfo) const |
|
362 { |
|
363 // Fill in the TNifIfInfo::iName field, which is used by TCP/IP |
|
364 if (iProtoBinders.Count()) |
|
365 { |
|
366 //[401TODO] RZ: we're probably need fixed array to avoid index changing |
|
367 iProtoBinders[0]->GetName(aInfo.iName); |
|
368 |
|
369 if(!iInterfaceNameRecorded) |
|
370 { |
|
371 XInterfaceNames* itfNames = static_cast<XInterfaceNames*>( |
|
372 const_cast<Meta::SMetaData*>(iProtoBinders[0]->Flow().AccessPointConfig().FindExtension(XInterfaceNames::TypeId()))); |
|
373 itfNames->AddInterfaceNameL(this, aInfo.iName); |
|
374 iInterfaceNameRecorded = ETrue; |
|
375 } |
|
376 } |
|
377 |
|
378 //[401TODO] DL: get rid of magic number |
|
379 aInfo.iVersion = TVersion(78,96,12453); |
|
380 |
|
381 } |
|
382 |
|
383 TInt CIPShimIfBase::Send(RMBufChain& aPdu, TAny* /*aSource*/) |
|
384 /** |
|
385 Called from upper protocol to send a data packet. |
|
386 |
|
387 @param aPdu packet to send |
|
388 @param aSource unused |
|
389 @return 0 if upper protocol should block until receipt of StartSending(), else 1. |
|
390 */ |
|
391 { |
|
392 // demultiplex packets into the approriate senders |
|
393 const RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPdu); |
|
394 CIPProtoBinder *binder = reinterpret_cast<CIPProtoBinder*>(info->iDstAddr.Port()); |
|
395 |
|
396 //[401TODO] This check is there purely because of GuQoS interoperability |
|
397 //i.e.: GuQoS colloring packets for the Flow below IPShim. Get rid of |
|
398 //this if statement along with GuQoS. |
|
399 if (iProtoBinders.Count() == 1 || binder == NULL) |
|
400 { |
|
401 return iProtoBinders[0]->Send(aPdu); |
|
402 } |
|
403 else |
|
404 { |
|
405 return binder->Send(aPdu); |
|
406 } |
|
407 } |
|
408 |
|
409 TInt CIPShimIfBase::Notification(TAgentToNifEventType /*aEvent*/, void * /*aInfo*/) |
|
410 /** |
|
411 */ |
|
412 { |
|
413 return KErrNotSupported; |
|
414 } |
|
415 |
|
416 void CIPShimIfBase::SetConnectionInfo(const TConnectionInfo& aConnectionInfo) |
|
417 /** |
|
418 Called from the Flow to provision the connection info to us. |
|
419 */ |
|
420 { |
|
421 iConnectionInfo = aConnectionInfo; |
|
422 } |
|
423 |
|
424 const TConnectionInfo& CIPShimIfBase::ConnectionInfo() |
|
425 /** |
|
426 Called from the Flow to provision the connection info to us. |
|
427 */ |
|
428 { |
|
429 return iConnectionInfo; |
|
430 } |
|
431 |
|
432 const TDesC8& CIPShimIfBase::ProtocolName() |
|
433 /** |
|
434 Return the associated protocol name. |
|
435 */ |
|
436 { |
|
437 ASSERT(iProtocolName.Length()); |
|
438 return iProtocolName; |
|
439 } |
|
440 |
|
441 |
|
442 void CIPShimIfBase::AddIpAddrInfoL(CIPProtoBinder* aBinder, CSubConIPAddressInfoParamSet::TSubConIPAddressInfo& aAddrInfo) |
|
443 { |
|
444 ASSERT(iHookAddressInfo); |
|
445 iHookAddressInfo->AddL(aBinder, aAddrInfo); |
|
446 } |
|
447 |
|
448 void CIPShimIfBase::RemoveIpAddrInfo(CIPProtoBinder* aBinder, CSubConIPAddressInfoParamSet::TSubConIPAddressInfo& aAddrInfo) |
|
449 { |
|
450 ASSERT(iHookAddressInfo); |
|
451 iHookAddressInfo->Remove(aBinder, aAddrInfo); |
|
452 } |
|
453 |
|
454 void CIPShimIfBase::RemoveIpAddrInfo(CIPProtoBinder* aBinder) |
|
455 { |
|
456 if (iHookAddressInfo) |
|
457 { |
|
458 iHookAddressInfo->Remove(aBinder); |
|
459 } |
|
460 } |
|
461 |
|
462 |
|
463 CIPShimSubConnectionFlow& CIPShimIfBase::Flow() |
|
464 { |
|
465 ASSERT(iProtoBinders.Count() > 0); |
|
466 return iProtoBinders[0]->Flow(); |
|
467 } |
|
468 |
|
469 CIPShimProtocolIntf* CIPShimIfBase::ProtcolIntf() |
|
470 { |
|
471 ASSERT(iProtIntf); |
|
472 return iProtIntf; |
|
473 } |