networkcontrol/ipnetworklayer/src/IPProtoTierManagerSelector.cpp
changeset 0 af10295192d8
child 20 7e41d162e158
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/ipnetworklayer/src/IPProtoTierManagerSelector.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,883 @@
+// Copyright (c) 2006-2009 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:
+// This is part of an ECOM plug-in
+// 
+//
+
+#include "IPProtoTierManagerSelector.h"
+#include "IPProtoTierManagerFactory.h"
+#include "IPProtoMCpr.h"
+#include <comms-infras/ss_log.h>
+#include <ss_glob.h>
+#include <comms-infras/ss_tiermanagerutils.h>
+#include <commsdattypesv1_1.h> // CommsDat
+#include <es_connpref.h>	//TConnIdList
+#include <commdbconnpref.h>	//TCommDbConnPref & TCommDbConnPrefMulti
+
+#include <comms-infras/esock_params_internal.h>  //TConnCSRParams
+#include <comms-infras/ss_mcprnodemessages.h> //RConnPrefList and Iterator
+#include <comms-infras/esock_params.h>
+#include <comms-infras/ss_metaconnprov_internal.h>
+#include <comms-infras/simpleselectorbase.h>
+#include <commsdattypesv1_1_partner.h>
+
+#ifdef _DEBUG
+#define KIpProtoTierMgrTag KESockMetaConnectionTag
+_LIT8(KIpProtoTierMgrSubTag, "ipprototiermgr");
+#endif
+
+using namespace ESock;
+using namespace CommsDat;
+
+const TInt KCommsdatLinkFlag    =  0x80000000;
+
+
+//Panic codes
+_LIT(KIpProtoSelectorPanic, "IpProtoSelector");
+enum TIpProtoSelectorPanic
+	{
+	EExpectedAccessPointAwareSystem = 0,
+	EUnExpectedSelectionPreferences = 1,
+	EUnExpectedNumberOfAccessPoints = 2
+    };
+
+TUint FindIPProtoAccessPointForIAPL(TUint aIap, CMDBSession* aDbs)
+	{
+	CCDAccessPointRecord* apRec = static_cast<CCDAccessPointRecord*>(CCDTierRecord::RecordFactoryL(KCDTIdAccessPointRecord));
+	CleanupStack::PushL(apRec);
+	apRec->iCprConfig = aIap;
+	apRec->iTier = CIPProtoTierManagerFactory::iUid | KCommsdatLinkFlag;
+	
+	TUint ap = 0;
+	TBool found = apRec->FindL(*aDbs);
+	if (found)
+		{
+		ap = apRec->iRecordTag;
+		}
+	else
+		{
+		ap = TierManagerUtils::ReadDefaultAccessPointL(TUid::Uid(CIPProtoTierManagerFactory::iUid), *aDbs);
+		}
+	CleanupStack::PopAndDestroy(apRec);
+	
+	return ap;
+	}
+
+
+CMetaConnectionProviderBase* AIpProtoSelectorBase::FindOrCreateProviderL(TUint aIapToFind, TUint aAccessPointToCreate)
+	{
+	//Find factory
+	TUid mCprUid = TierManagerUtils::ReadMCprUidL(aAccessPointToCreate,*iDbs);
+	CMetaConnectionProviderFactoryBase* factory = static_cast<CMetaConnectionProviderFactoryBase*>(iMetaContainer.FindOrCreateFactoryL(mCprUid));
+
+	//Create the provider
+	TUid tierId = TUid::Uid(iTierRecord->iRecordTag);
+	TUid tierImplUid = TUid::Uid(iTierRecord->iTierImplUid);
+	TProviderInfo providerInfo(tierId,aIapToFind);
+	TMetaConnectionFactoryQuery query(providerInfo,tierImplUid);
+	CMetaConnectionProviderBase* provider = static_cast<CMetaConnectionProviderBase*>(factory->Find(query));
+	if (provider==NULL)
+		{
+		//If this is an attach selection, the provider must be found, so leave with an error
+		if (iSelectionPrefs.Scope()&TSelectionPrefs::ESelectFromExisting)
+	    	{
+			//For legacy reasons only, we need to return KErrCouldNotConnect instead of KErrNotFound
+			//for leagcy attach (legacy attach uses EConnPrefCommDb).
+			User::Leave(iSelectionPrefs.Prefs().ExtensionId() == TConnPref::EConnPrefCommDb ? KErrCouldNotConnect : KErrNotFound);
+	       	}
+
+       	//For construction of IpProto providers (construction only) we use the instance field of TProviderInfo
+       	//to carry the IAP id. The IAP id is necessary fo the provider to initialise itself from the database.
+       	TMetaConnectionFactoryQuery query(TProviderInfo(tierId,aAccessPointToCreate,(TAny*)aIapToFind),tierImplUid);
+       	provider = static_cast<CMetaConnectionProviderBase*>(factory->CreateObjectL(query));
+   		}
+
+	if (!(iSelectionPrefs.Scope()&TSelectionPrefs::ESelectFromExisting))
+		{
+		CIPProtoMetaConnectionProvider *ipprotomcpr = static_cast<CIPProtoMetaConnectionProvider *>(provider);
+		if (ipprotomcpr->iIapLocked)
+			User::Leave(KErrPermissionDenied);
+
+		TSecureId sid;
+		ASubSessionPlatsecApiExt platsecext(iSelectionPrefs.SubSessionUniqueId());
+		if (platsecext.SecureId(sid) == KErrNone)
+			{
+			CCommsDatIapView* iapView = CCommsDatIapView::NewLC(aIapToFind);
+
+			TUint32 iapsid;
+			iapView->GetIntL(KCDTIdIAPAppSid, iapsid);
+
+			if (sid.iId == iapsid && iapsid != 0)
+				ipprotomcpr->iIapLocked = ETrue;
+			CleanupStack::PopAndDestroy(iapView);
+			}
+		}
+	provider->IncrementBlockingDestroy();
+	return provider;
+	}
+
+//
+//CIpProtoProviderSelector
+
+void CIpProtoProviderSelector::RunL()
+	// The dialogue has been presented.
+	// Normally completes with KErrNone or KErrCancel
+	// Could, however, complete with another system error e.g. KErrOutOfMemory
+	{
+	TInt error = iStatus.Int();
+	__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("CIpProtoProviderSelector %08x::\tRunL() Err%d Ap%d"),this, error, SelectedIAP()));
+    User::LeaveIfError(error);
+
+    ASSERT(SelectedIAP()); //Should not be 0 now.
+    
+    TConnPref& pref = iSelectionPrefs.Prefs();
+    const TConnIdList& list = static_cast<const TConnIdList&>(pref);
+    TUint accessPoint = list.Get(0);
+    
+    //finish the selection which the prompt was for
+    CMetaConnectionProviderBase* ipprotoMCPr = FindOrCreateProviderL(SelectedIAP(), FindIPProtoAccessPointForIAPL(SelectedIAP(), iDbs));
+    TLayerSelectionInfo* selectionInfo = const_cast<TLayerSelectionInfo*>(
+            static_cast<const TLayerSelectionInfo*>(ipprotoMCPr->AccessPointConfig().FindExtension(
+            		STypeId::CreateSTypeId(TLayerSelectionInfo::EUid, TLayerSelectionInfo::ETypeId))));
+    __ASSERT_ALWAYS(selectionInfo, User::Panic(_L("ipproto"), CorePanics::KPanicUnexpectedExecutionPath));
+    
+    if ((TUint)-1 == selectionInfo->CustomSelectionPolicy())
+    	{
+    	/*
+		 * This means that the default IPProto AP is used from the meshpreface.cfg file,
+		 * which has a -1 as the CustomSelectionPolicy (the reason for that is that we don't know
+		 * which will be the default IAP, default Link level AP, so that's why we prompted for that).
+		 * This is the place and time we know how to overwrite the AccessPoint information of the MCPr
+		 * meaning we know the selected IAP. So the -1 value can be overwritten with the selected recordID,
+		 * or tagID of the Link level AP.
+		 */
+		selectionInfo->iCustomSelectionPolicy = SelectedIAP();
+    	selectionInfo->iCprConfig = SelectedIAP();
+    	}
+    
+    iSelectionNotify.SelectComplete(this,ipprotoMCPr);
+	//iSelectionNotify.SelectComplete(this,FindOrCreateProviderL(SelectedIAP(), FindIPProtoAccessPointForIAPL(SelectedIAP(), iDbs)));
+	
+    //store the information that we have already prompted the user
+    TPromptingSelectionPrefsExt* promptingExt = const_cast<TPromptingSelectionPrefsExt*>(
+            static_cast<const TPromptingSelectionPrefsExt*>(iNetworkMCpr->AccessPointConfig().FindExtension(
+                    TPromptingSelectionPrefsExt::TypeId())));
+	if (promptingExt == NULL)
+		{
+		/*
+		 * the extension is not existing yet on the AccessPointConfig of the NetMCPr. Append a new one
+		 * to indicate that we have already prompted the user. So if the configuration contains 2
+		 * ConnectionPreferences record without any default IAP and with PROPTING dialog preference then
+		 * the prompt dialog won't be invoked in the 2nd time but only during the re-selection, if it's needed.
+		 */
+	    RMetaExtensionContainer mec;
+	    mec.Open(iNetworkMCpr->AccessPointConfig());
+	    CleanupClosePushL(mec);
+	    
+	    TConnIdList dummyList;
+		TPromptingSelectionPrefsExt* ext = new (ELeave) TPromptingSelectionPrefsExt(TUid::Uid(iTierRecord->iRecordTag),dummyList); //it's an empty list
+		CleanupStack::PushL(ext);
+		mec.AppendExtensionL(ext);
+        CleanupStack::Pop(ext);
+
+		iNetworkMCpr->AccessPointConfig().Close();
+		iNetworkMCpr->AccessPointConfig().Open(mec);
+		CleanupStack::PopAndDestroy(&mec);
+		}
+	else if (!promptingExt->iPromptingInProgress)
+	    {
+	    promptingExt->iPromptingInProgress = ETrue;
+	    }
+	else
+		{
+		/* the extension is existing already on the AccessPointConfig of the NetMCPr.
+		 * This means that this is was the 2nd time we have prompted. Mark the extension
+		 * to indicate that we don't have any more choices...
+		 */
+		promptingExt->iPromptingInProgress = EFalse;
+		}
+	
+	//Complete the selection request
+	iSelectionNotify.SelectComplete(this,NULL);
+	}
+
+TInt CIpProtoProviderSelector::RunError(TInt aError)
+	{
+	iSelectionNotify.Error(this,aError);
+	return KErrNone;
+	}
+
+void CIpProtoProviderSelector::InvokeDialogL(ISelectionNotify& aSelectionNotify,
+		                                     TUint aCprConfig)
+	{
+	TConnectionPrefs prefsForPromt;
+	TierManagerUtils::GetPrefsFromConnPrefRecL(aCprConfig, *iDbs, prefsForPromt);
+	
+	PromptUserL(aSelectionNotify, prefsForPromt);
+	}
+
+void CIpProtoProviderSelector::SelectL(ISelectionNotify& aSelectionNotify)
+	{
+	ASSERT(iDbs);
+	ASSERT(iTierRecord);
+	TUint32 defaultAccessPoint = iTierRecord->iDefaultAccessPoint;
+
+	//Must be set
+	__ASSERT_DEBUG(defaultAccessPoint!=0,User::Panic(KIpProtoSelectorPanic,EExpectedAccessPointAwareSystem));
+	User::LeaveIfError(defaultAccessPoint!=0? KErrNone : KErrCorrupt);
+
+	TConnPref& pref = iSelectionPrefs.Prefs();
+	//This selector receives only EConnPrefIdList at this layer
+	__ASSERT_DEBUG(pref.ExtensionId() == TConnPref::EConnPrefIdList, User::Panic(KIpProtoSelectorPanic,EUnExpectedSelectionPreferences));
+
+	__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("CIpProtoProviderSelector %08x::\tSelectL() Using TConnIdList"),this));
+	const TConnIdList& list = static_cast<const TConnIdList&>(pref);
+
+	TUint apElemId = 0;
+	TUint cprConfig = 0;
+	TUint custSelPol = 0;
+	
+	TInt count = list.Count();
+	for (TInt i = 0; i < count; i++)
+		{
+		TUint accessPoint = list.Get(i);
+		
+		cprConfig  = TierManagerUtils::ReadCprConfigL(accessPoint, *iDbs);
+		custSelPol = TierManagerUtils::ReadCustomSelectionPolicyIdL(accessPoint, *iDbs);
+		
+		if ( (KCDTIdConnectionPrefsRecord == (KCDMaskShowRecordType & cprConfig)) ||
+			 ((TUint)-1 == custSelPol) )
+			{
+			/* 1.)
+			 * There is a full TMDBelementID in the cprConfig field of the given AP. 
+			 * This means that the related ConnPref record is a prompting record so
+			 * this AP is a so-called 'prompring AP. Invoke a dialog prompt.
+			 * 
+			 * 2.)
+			 * The default IPProto AP is used form the meshpreface.cfg file, where
+			 * there isn't any connectionPrefs record in the database. We should invoke
+			 * a dialog in this case too to get back the tagID of the Linke level AP, which
+			 * is the same as recordID of the used IAP.
+			 * 
+			 */
+			
+		    TPromptingSelectionPrefsExt* promptingExt = const_cast<TPromptingSelectionPrefsExt*>(
+		            static_cast<const TPromptingSelectionPrefsExt*>(iNetworkMCpr->AccessPointConfig().FindExtension(
+		                    TPromptingSelectionPrefsExt::TypeId())));
+		    if (promptingExt)
+				{
+				/* our NetMCPr has a prompting extension already. This can mean 2 things:
+				 * 1.) We are still in the selection process and we have 2 prompting APs on
+				 * 	   the IPProto level. In this case now (2nd time) don't invoke any further
+				 *     dialog but store the information in the NetMCPr that we have still 1
+				 *     possibility for the re-selection scenario.
+				 * 2.) This is the re-selection scenario, so we have to invoke the prompt
+				 *     dialog.
+				 */
+				
+				if (!iReselection)
+					{
+					//the 1.) paragraph is true
+					TConnIdList list;
+					list.Append(accessPoint);
+					
+					promptingExt->iPrefs = list;
+					promptingExt->iTierId = TUid::Uid(iTierRecord->iRecordTag);
+					promptingExt->iPromptingInProgress = ETrue;
+					}
+				else
+					{
+					//the 2.) paragraph is true
+					//invoke a dialog
+					InvokeDialogL(aSelectionNotify, cprConfig);
+					return; //selection will continue in the RunL
+					}
+				}
+			else
+				{
+				//invoke a dialog
+				InvokeDialogL(aSelectionNotify, cprConfig);
+				return; //selection will continue in the RunL
+				}
+			}
+		else
+			{
+			/*
+			 * business as usual
+			 */
+			TPromptingSelectionPrefsExt* promptingExt = const_cast<TPromptingSelectionPrefsExt*>(
+                static_cast<const TPromptingSelectionPrefsExt*>(iNetworkMCpr->AccessPointConfig().FindExtension(
+                    TPromptingSelectionPrefsExt::TypeId())));
+    		if (promptingExt != NULL)
+				{
+				/* There is a prompting extension in the AccessPointConfig of our
+				 * Network MCPr. This means that there are 2 ConnPref records in the
+				 * database. The first one is a prompting one (that's why the extension is there
+				 * - to indicate that we have already prompted). But the 2nd record is
+				 * not a prompting record, so the mapped IPProto AP is _NOT_ a prompting AP.
+				 * Continue the selection as usual, and mark the extension - it's not
+				 * needed anymore because if there will be a re-selection we can't use
+				 * the extension as the 2nd IPProto AP is not a promting one.
+				 */
+				promptingExt->iPromptingInProgress = EFalse;
+				}
+			
+			//apElemId = TierManagerUtils::ReadCustomSelectionPolicyIdL(accessPoint,*iDbs);
+			apElemId = TierManagerUtils::ReadCprConfigL(accessPoint,*iDbs);
+			aSelectionNotify.SelectComplete(this,FindOrCreateProviderL(apElemId,accessPoint));
+			}
+		} //for
+
+	//Complete the selection request
+	aSelectionNotify.SelectComplete(this,NULL);
+	}
+
+
+//
+//CIpProtoProviderSelectorConnPrefList
+CIpProtoProviderSelectorConnPrefList::CIpProtoProviderSelectorConnPrefList(const ESock::RConnPrefList& aSelectionPreferences)
+	:	AIpProtoSelectorBase()
+	,	iSelectionPrefList(aSelectionPreferences)
+	,	iTierId(TUid::Uid(CIPProtoTierManagerFactory::iUid))
+	,	iLastAccessPoint(0)
+		{
+		}
+
+void CIpProtoProviderSelectorConnPrefList::RunL()
+	// The dialogue has been presented.
+	// Normally completes with KErrNone or KErrCancel
+	// Could, however, complete with another system error e.g. KErrOutOfMemory
+	{
+	TInt error = iStatus.Int();
+	__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("CIpProtoProviderSelector %08x::\tRunL() Err%d Ap%d"),this, error, SelectedIAP()));
+    User::LeaveIfError(error);
+
+    ASSERT(SelectedIAP()); //Should not be 0 now.
+    
+    //finish the selection which the prompt was for
+	iSelectionNotify.SelectComplete(this,FindOrCreateProviderL(SelectedIAP(), iLastAccessPoint));
+	
+    //--------------------------------------------------
+    //continue the loop which we started in the SelectL
+    //--------------------------------------------------
+    ESock::RConnPrefList::TIter<TConnAPPref> iterAP = iSelectionPrefList.getIter<TConnAPPref>();
+    
+	CCDAccessPointRecord* apRec;
+	TUid tierId;
+	TInt cprConfig = 0;
+	
+//This iterator runs through all the instances of TConnAPPref
+	while(!iterAP.IsEnd())
+		{
+		//Access point is retrived from preference
+		TUint accessPoint = iterAP->GetAP();
+		//The record relating to this access point is retrived
+		apRec = TierManagerUtils::LoadAccessPointRecordL(accessPoint,*iDbs);
+		//A check is done to confirm the access point is related to this tier
+		//tierId = TUid::Uid(apRec->iTier);
+		tierId = TierManagerUtils::MapElementIdToTagId(apRec->iTier, *iDbs);
+		
+		delete apRec;
+		if(iTierId == tierId)
+			{
+			//The iap related to the access point is retrived from the record
+			//This iap must be created at the link layer, within the method
+			//FindOrCreateProviderL the provider created is provisioned with this
+			//iap, this means when the next tier is created the appropriate iap will
+			//be created
+			
+			cprConfig =  TierManagerUtils::ReadCprConfigL(accessPoint,*iDbs);
+			
+			if (KCDTIdConnectionPrefsRecord == (KCDMaskShowRecordType & cprConfig))
+				{
+				/* There is a full TMDBelementID in the cprConfig field of the given AP.
+				 * This means that the related ConnPref record is a prompting record so
+				 * this AP is a so-called 'prompring AP. As we are in the RunL method
+				 * this means that we've invoked already a dilog prompt so here we cannot
+				 * invoke another one. Instead store the information that we have still
+				 * possibilies in the case of a reconnection.
+				 */
+				TConnIdList list;
+				list.Append(accessPoint);
+				
+				RMetaExtensionContainer mec;
+				mec.Open(iNetworkMCpr->AccessPointConfig());
+				CleanupClosePushL(mec);
+				
+				TPromptingSelectionPrefsExt* ext = new (ELeave) TPromptingSelectionPrefsExt(TUid::Uid(iTierRecord->iRecordTag),list); //it's an empty list
+				CleanupStack::PushL(ext);
+				mec.AppendExtensionL(ext);
+				CleanupStack::Pop(ext);
+				
+				iNetworkMCpr->AccessPointConfig().Close();
+				iNetworkMCpr->AccessPointConfig().Open(mec);
+				CleanupStack::PopAndDestroy(&mec);
+				}
+			else
+				{
+				iSelectionNotify.SelectComplete(this,FindOrCreateProviderL(cprConfig, accessPoint));
+				}
+			//The peference is no longer needed so is deleted and removed
+			delete iterAP.Remove();
+			}
+		else
+			{
+			iterAP++;
+			}
+		}
+	iSelectionNotify.SelectComplete(this,NULL);
+	}
+
+TInt CIpProtoProviderSelectorConnPrefList::RunError(TInt aError)
+	{
+	iSelectionNotify.Error(this,aError);
+	return KErrNone;
+	}
+
+void CIpProtoProviderSelectorConnPrefList::SelectL(ISelectionNotify& aSelectionNotify)
+	{
+	iDbs = CMDBSession::NewL(KCDVersion1_2);
+	iTierRecord = TierManagerUtils::LoadTierRecordL(iTierId,*iDbs);
+
+	ASSERT(iTierRecord);
+
+	CCDAccessPointRecord* apRec;
+	TUid tierId;
+
+	ESock::RConnPrefList::TIter<TConnCSRPref> iterCSR = iSelectionPrefList.getIter<TConnCSRPref>();
+	ASSERT(iterCSR[0] != NULL || iterCSR[1] == NULL );
+	iSelectionPrefs.SetScope(iterCSR[0]->Scope());
+	iSelectionPrefs.SetFlags(iterCSR[0]->Flags());
+	iSelectionPrefs.SetSubSessionUniqueId(iterCSR[0]->SubSessionUniqueId());
+	
+	TInt cprConfig = 0;
+	
+	ESock::RConnPrefList::TIter<TConnAPPref> iterAP = iSelectionPrefList.getIter<TConnAPPref>();
+
+	//This iterator runs through all the instances of TConnAPPref
+	while(!iterAP.IsEnd())
+		{
+		//Access point is retrived from preference
+		TUint accessPoint = iterAP->GetAP();
+		//The record relating to this access point is retrived
+		apRec = TierManagerUtils::LoadAccessPointRecordL(accessPoint,*iDbs);
+		//A check is done to confirm the access point is related to this tier
+		//tierId = TUid::Uid(apRec->iTier);
+		tierId = TierManagerUtils::MapElementIdToTagId(apRec->iTier, *iDbs);
+		
+		delete apRec;
+		if(iTierId == tierId)
+			{
+			//The iap related to the access point is retrived from the record
+			//This iap must be created at the link layer, within the method
+			//FindOrCreateProviderL the provider created is provisioned with this
+			//iap, this means when the next tier is created the appropriate iap will
+			//be created
+			
+			cprConfig =  TierManagerUtils::ReadCprConfigL(accessPoint,*iDbs);
+			
+			if (KCDTIdConnectionPrefsRecord == (KCDMaskShowRecordType & cprConfig))
+				{
+				/* There is a full TMDBelementID in the cprConfig field of the given AP.
+				 * This means that the related ConnPref record is a prompting record so
+				 * this AP is a so-called 'prompring AP. Invoke a dialog prompt.
+				 */
+				//invoke a dialog
+				
+				TConnectionPrefs prefsForPromt;
+				TierManagerUtils::GetPrefsFromConnPrefRecL(cprConfig, *iDbs, prefsForPromt);
+				
+				PromptUserL(aSelectionNotify, prefsForPromt);
+				
+				/* Remove the last processed preference so the loop in the
+				 * RunL can continue from the beginning of the list
+				 */
+				delete iterAP.Remove();
+				iLastAccessPoint = accessPoint;
+				return; //selection will continue in the RunL
+				}
+			else
+				{
+				aSelectionNotify.SelectComplete(this,FindOrCreateProviderL(cprConfig, accessPoint));
+				}
+			//The peference is no longer needed so is deleted and removed
+			delete iterAP.Remove();
+			}
+		else
+			{
+			iterAP++;
+			}
+		}
+	aSelectionNotify.SelectComplete(this,NULL);
+	}
+
+
+//
+//CLinkPrefsSelector
+CLinkPrefsSelector::~CLinkPrefsSelector()
+	{
+	iPrefsList.Reset();
+	iPrefsList.Close();
+	}
+
+void CLinkPrefsSelector::SelectL(ISelectionNotify& aSelectionNotify)
+	{
+	ASSERT(iDbs);
+	ASSERT(iTierRecord);
+	ASSERT(iLegacyMCpr); //This selector depends on the legacy MCpr (client) being set!
+	iSelectionNotify = aSelectionNotify; //Store notify interface for asynch processing
+	TUint32 defaultAccessPoint = iTierRecord->iDefaultAccessPoint;
+
+	//Must be set
+	__ASSERT_DEBUG(defaultAccessPoint!=0,User::Panic(KIpProtoSelectorPanic,EExpectedAccessPointAwareSystem));
+	User::LeaveIfError(defaultAccessPoint!=0? KErrNone : KErrCorrupt);
+
+	if (!iSelectionPrefs.IsEmpty() && iSelectionPrefs.Prefs().ExtensionId() == TConnPref::EConnPrefCommDb)
+		{ //There is only ever going to be one AP (Ip layer) as a result of these prefs.
+		//IAP based attach should follow this branch as well and takes the same route as
+		//ordinary selection (at this layer only)
+		TCommDbConnPref connPrefs = static_cast<const TCommDbConnPref&>(iSelectionPrefs.Prefs());
+		__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("CLinkPrefsSelector %08x::\tSelectL() Using TCommDbConnPref, IAP:%d"),this,connPrefs.IapId()));
+		OverrideLegacyPrefs(connPrefs,1);
+		iPrefsList.AppendL(connPrefs);
+		}
+	else if (!iSelectionPrefs.IsEmpty() && iSelectionPrefs.Prefs().ExtensionId() == TConnPref::EConnPrefCommDbMulti)
+		{ //There may be multiple APs (Ip layer) as a result of these prefs.
+		const TCommDbMultiConnPref& connPrefsMulti = static_cast<const TCommDbMultiConnPref&>(iSelectionPrefs.Prefs());
+		TInt attempts = const_cast<TCommDbMultiConnPref&>(connPrefsMulti).ConnectionAttempts();
+		ASSERT(attempts >= 0 && attempts <= TCommDbMultiConnPref::KMaxMultiConnPrefCount); //Sanity check
+		__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("CLinkPrefsSelector %08x::\tSelectL() Using TCommDbMultiConnPref, attempts:%d"),this,attempts));
+		//Be careful, TCommDbMultiConnPref takes a special index that starts from 1!
+		for (TInt i = 1; i <= attempts; i++)
+			{
+			TCommDbConnPref connPrefs;
+			User::LeaveIfError(const_cast<TCommDbMultiConnPref&>(connPrefsMulti).GetPreference(i,connPrefs));
+			OverrideLegacyPrefs(connPrefs,i);
+			iPrefsList.AppendL(connPrefs);
+			}
+		}
+	else
+		{
+		//We must have link layer prefs here!
+		User::Panic(KIpProtoSelectorPanic,EUnExpectedSelectionPreferences);
+		}
+
+	//From this point on we attempt to mimic the legacy netcon/nifman selection logic.
+	//All preferences are now stored in the iPrefsList and for our legacy scenarios
+	//the list can not be empty.
+	ASSERT(iPrefsList.Count()>0);
+	User::LeaveIfError(iPrefsList.Count()>0? KErrNone : KErrArgument);
+	ProcessPrefsFromListL();
+	}
+
+void CLinkPrefsSelector::OverrideLegacyPrefs(TCommDbConnPref& aConnPrefs, TInt aRank)
+	{
+	//A short guide to legacy overrides, in chronological order.
+	//1) If direction preferences == ECommDbConnectionDirectionUnknown,
+	//use ECommDbConnectionDirectionOutgoing, otherwise keep the prefs
+	//2) If iap == 0,
+	//GetPreferedIap(direction,attempt)
+	//3) If iap == 0 and ECommDbDialogPrefUnknown,
+	//set the dialog preference to ECommDbDialogPrefPrompt
+	//4) If dialog preference == ECommDbDialogPrefUnknown,
+	//use setting from the CCDTierRecord, otherwise keep the prefs
+	//5) If bearer preferences == ECommDbBearerUnknown,
+	//use the one from the IAP record, oterwise keep the prefs
+	//6) If dialog preference == ECommDbDialogPrefDoNotPrompt and iap == 0,
+	//use default from the CCDTierRecord record
+	//Finally, for multiple preferences, or when the dialog is used,
+	//we disallow (remove) repetitions.
+	//The rest of the legacy selection logic is in the legacy reconnection
+	//activity.
+	if (aConnPrefs.Direction()==ECommDbConnectionDirectionUnknown)
+		{
+		aConnPrefs.SetDirection(ECommDbConnectionDirectionOutgoing);
+		}
+	if (aConnPrefs.IapId()==0)
+		{
+		//Ignore if the record does not exist, aConnPrefs state should not change
+		TRAP_IGNORE(TierManagerUtils::MapRankingAndDirectionToPrefsL(aRank,aConnPrefs.Direction(),aConnPrefs,*iDbs));
+		}
+	if (aConnPrefs.IapId()==0 && aConnPrefs.DialogPreference()==ECommDbDialogPrefUnknown)
+		{
+		aConnPrefs.SetDialogPreference(ECommDbDialogPrefPrompt);
+		}
+	if (aConnPrefs.DialogPreference()==ECommDbDialogPrefUnknown)
+		{
+		TBool promptUser = iTierRecord->iPromptUser;
+		aConnPrefs.SetDialogPreference(promptUser? ECommDbDialogPrefPrompt : ECommDbDialogPrefDoNotPrompt);
+		}
+	if (aConnPrefs.BearerSet()==ECommDbBearerUnknown)
+		{
+		}
+	if (aConnPrefs.IapId()==0 && aConnPrefs.DialogPreference()==ECommDbDialogPrefDoNotPrompt)
+		{
+		aConnPrefs.SetIapId(iTierRecord->iDefaultAccessPoint);
+		}
+	}
+
+
+void CLinkPrefsSelector::ProcessPrefsFromListL()
+	{
+	//There may be more than one preference in the list (usually one or two).
+	//Some of them may have their dialog preference as ECommDbDialogPrefDoNotPrompt,
+	//some may have ECommDbDialogPrefPrompt.
+
+	//To code this selection behaviour as close to the legacy netcon's/nifman's
+	//logic as possible, we have taken the following approach:
+	//1) We select as much from the preference list as possible without invoking a dialog.
+	//2) If the selection is completed (iToBeSelected is empty) we finish, otherwise
+	//3) We prompt for the preferences that need to be prompted for
+	//4) If the dialog failed (has been cancelled, etc) we finish with an error, otherwise
+	//5) If the selection is completed (iToBeSelected is empty) we finish, otherwise
+	//6) We find the NetMCpr and store all remaining iToBeSelected entries in its configuration data
+	//Later, during legacy reconnection, these stored entries will be used by the legacy NetMCpr
+	//to extend its meta tree by nodes that could not be selected here at this time.
+
+	//If there is more than one preference in the queue, we will only ever prompt once, for the first one.
+	ASSERT(iPrefsList.Count());
+
+	//Take the first preference (see above for details)
+	TCommDbConnPref connPrefs = iPrefsList[0];
+	iPrefsList.Remove(0); //We do not want to consider this option again
+
+	__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("CLinkPrefsSelector %08x\tProcessPrefsFromListL DialogPreference: %d"), this, connPrefs.DialogPreference()));
+
+	//We are here only because DialogPreference()!=ECommDbDialogPrefDoNotPrompt
+ 	if (connPrefs.DialogPreference()==ECommDbDialogPrefDoNotPrompt ||
+ 		connPrefs.DialogPreference()==ECommDbDialogPrefPromptIfWrongMode)
+		{
+		SetSelectedIAP(connPrefs.IapId());
+		RunL();
+		}
+	else
+		{
+		//We have to involve dialog
+		User::LeaveIfError(iDlgServ.Connect());
+		TConnectionPrefs dialogPrefs;
+		dialogPrefs.iRank = 1;
+		dialogPrefs.iDirection = connPrefs.Direction();
+		dialogPrefs.iBearerSet = connPrefs.BearerSet();
+		// pass in iSelectedAPId directly here, as it's being passed in as a
+		// TUint32& and so IapConnection may wish to modify it.
+		iDlgServ.IapConnection(iSelectedAPId,dialogPrefs,iStatus);
+		SetActive();
+		iUserPromted = ETrue;
+		}
+	}
+
+void CLinkPrefsSelector::RunL()
+	{
+	if (iUserPromted)
+		{
+    	TInt error = iStatus.Int();
+    	if (error!=KErrNone)
+    		{
+	    	//The dialog has most likely been cancelled, etc
+	    	//This means no more selection, complete the selection request as it stands
+	    	iSelectionNotify.Error(this,error);
+	    	return;
+	    	}
+	    }
+
+    ASSERT(SelectedIAP()); //Must not be 0 now. Check your commsdat if it is.
+    ASSERT(iTierRecord);
+
+    //Report
+    iSelectionNotify.SelectComplete(this,FindOrCreateProviderL(SelectedIAP(),FindIPProtoAccessPointForIAPL(SelectedIAP(), iDbs)));
+
+	//Selection has not finished yet, so decide what to do next
+	if (iPrefsList.Count()>0)
+		{
+		ASSERT(iPrefsList.Count()==1); //Well, in the legacy world you could not have more than two..
+		if (iUserPromted)
+			{ //We have already prompted the user, so store the rest of the preferences
+			//into legacy NetMCpr's configuration data.
+			ASSERT(iLegacyMCpr->AccessPointConfig().FindExtension(TDeferredSelectionPrefsExt::TypeId())==NULL);
+			
+			RMetaExtensionContainer mec;
+			mec.Open(iLegacyMCpr->AccessPointConfig());
+			CleanupClosePushL(mec);
+			
+			TDeferredSelectionPrefsExt* ext = new (ELeave) TDeferredSelectionPrefsExt(TUid::Uid(iTierRecord->iRecordTag),iPrefsList[0]);
+			iPrefsList.Close();
+			CleanupStack::PushL(ext);
+			mec.AppendExtensionL(ext);
+			CleanupStack::Pop(ext);
+			
+			iLegacyMCpr->AccessPointConfig().Close();
+			iLegacyMCpr->AccessPointConfig().Open(mec);
+			CleanupStack::PopAndDestroy(&mec);
+			}
+		else
+	    	{
+			//We have not prompted the user yet and the selection has not finished,
+			//proceed to the next preference.
+	    	ProcessPrefsFromListL();
+	    	return;
+			}
+		}
+
+   	//Selection has finished, regardless if we have prompted user or not, finish.
+   	iSelectionNotify.SelectComplete(this,NULL); //Complete the selection request
+	}
+
+TInt CLinkPrefsSelector::RunError(TInt aError)
+	{
+	//The iSelectionNotify must not be NULL now since it has been set in SelectL
+	iSelectionNotify.Error(this,aError);
+	return KErrNone;
+	}
+
+/**
+
+	Since Ip Proto providers need to carry their IAP's identification, we use two Ids
+	as parameters to this factory function:
+	One is used to find a provider at this layer (IAP id), the other is used to create
+	(and provision) a provider at this layer (for legacy selection it is the default
+	access point).
+*/
+CMetaConnectionProviderBase* CLinkPrefsSelector::FindOrCreateProviderL(TUint aIapToFind, TUint aAccessPointToCreate)
+	{
+	TUid mCprUid = TierManagerUtils::ReadMCprUidL(aAccessPointToCreate,*iDbs);
+	CMetaConnectionProviderFactoryBase* factory = static_cast<CMetaConnectionProviderFactoryBase*>(iMetaContainer.FindOrCreateFactoryL(mCprUid));
+
+	//Create the provider
+	TUid tierId = TUid::Uid(iTierRecord->iRecordTag);
+	TUid tierImplUid = TUid::Uid(iTierRecord->iTierImplUid);
+	TProviderInfo providerInfo(tierId,aIapToFind);
+	TMetaConnectionFactoryQuery query (providerInfo,tierImplUid);
+	CMetaConnectionProviderBase* provider = static_cast<CMetaConnectionProviderBase*>(factory->Find(query));
+	TBool providerCreated(EFalse);
+	if (provider==NULL)
+		{
+		//If this is an attach selection, the provider must be found, so leave with an error
+		if (iSelectionPrefs.Scope()&TSelectionPrefs::ESelectFromExisting)
+	    	{
+			//For legacy reasons only, we need to return KErrCouldNotConnect instead of KErrNotFound
+			//for leagcy attach (legacy attach uses EConnPrefCommDb).
+			User::Leave(iSelectionPrefs.Prefs().ExtensionId() == TConnPref::EConnPrefCommDb ? KErrCouldNotConnect : KErrNotFound);
+	       	}
+
+       	//For construction of IpProto providers (construction only) we use the instance field of TProviderInfo
+       	//to carry the IAP id. The IAP id is necessary fo the provider to initialise itself from the database.
+       	TMetaConnectionFactoryQuery query(TProviderInfo(tierId,aAccessPointToCreate,(TAny*)aIapToFind),tierImplUid);
+       	provider = static_cast<CMetaConnectionProviderBase*>(factory->CreateObjectL(query));
+       	providerCreated = ETrue; // See below - non obvious conditional late CleanupStack::Pop()
+        CleanupStack::PushL(provider);
+ 		if (aIapToFind != aAccessPointToCreate)
+ 			{
+ 			RMetaExtensionContainer mec;
+ 			mec.Open(provider->AccessPointConfig());
+ 			CleanupClosePushL(mec);
+ 			
+ 			//This IpProto provider must always go straight for the lower layer IAP.
+ 			//For that we need to override the selection policy.
+			TConnIdList list;
+			list.Append(aIapToFind);
+			TUid nextTierId = TierManagerUtils::ReadTierIdL(aIapToFind,*iDbs);
+			TOverridenSelectionPrefsExt* ext = new (ELeave) TOverridenSelectionPrefsExt(nextTierId,TSelectionPrefs(list));
+			CleanupStack::PushL(ext);
+			mec.AppendExtensionL(ext); //The ownership of the extension goes to AccessPointConfig now.
+			CleanupStack::Pop(ext);
+
+			provider->AccessPointConfig().Close();
+			provider->AccessPointConfig().Open(mec);
+			CleanupStack::PopAndDestroy(&mec);
+			}
+   		}
+
+	if (!(iSelectionPrefs.Scope()&TSelectionPrefs::ESelectFromExisting))
+		{
+		CIPProtoMetaConnectionProvider *ipprotomcpr = static_cast<CIPProtoMetaConnectionProvider *>(provider);
+		if (ipprotomcpr->iIapLocked)
+		    {
+			User::Leave(KErrPermissionDenied);
+		    }
+
+		TSecureId sid;
+		ASubSessionPlatsecApiExt platsecext(iSelectionPrefs.SubSessionUniqueId());
+		if (platsecext.SecureId(sid) == KErrNone)
+			{
+			CCommsDatIapView* iapView = CCommsDatIapView::NewLC(aIapToFind);
+
+			TUint32 iapsid;
+			iapView->GetIntL(KCDTIdIAPAppSid, iapsid);
+
+			if (sid.iId == iapsid && iapsid != 0)
+				ipprotomcpr->iIapLocked = ETrue;
+			CleanupStack::PopAndDestroy(iapView);
+			}
+		}
+	
+	if (providerCreated)
+	    {
+	    // New provider may have been created so remove from the cleanup here (after all the leaving methods)
+	    // When maintaining/altering code be aware of keeping the cleanup stack balanced 
+        CleanupStack::Pop(provider);
+	    }
+	
+	provider->IncrementBlockingDestroy();
+	return provider;
+	}
+
+
+//
+//TIpProtoProviderSelectorFactory::NewSelectorL - mapping prefs to a selector
+MProviderSelector* TIpProtoProviderSelectorFactory::NewSelectorL(const Meta::SMetaData& aSelectionPreferences)
+	{
+	__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("TIpProtoProviderSelectorFactory::\tNewSelectorL()")));
+	ASSERT(aSelectionPreferences.IsTypeOf(TSelectionPrefs::TypeId()));
+	const ESock::TSelectionPrefs& sp = static_cast<const ESock::TSelectionPrefs&>(aSelectionPreferences);
+	ASimpleSelectorBase* self = NULL;
+	CBase* selfCleanupItem = NULL;
+    
+	CMDBSession* dbs = CMDBSession::NewLC(KCDVersion1_2);
+
+
+	// Reveal hidden or private IAP records if a licensee has chosen to protect a record
+	// using one of these flags - the API to do this is public so internal components
+	// have to support the use of such records.
+	dbs->SetAttributeMask( ECDHidden | ECDPrivate );
+    
+	TBool prefLegacy = !sp.IsEmpty() && sp.Prefs().ExtensionId()!=TConnPref::EConnPrefSnap && sp.Prefs().ExtensionId()!=TConnPref::EConnPrefIdList;
+    
+	//Legacy selection (including legacy attach)
+	if (prefLegacy)
+		{
+		__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("TIpProtoProviderSelectorFactory::\tNewSelectorL() - Legacy selector")));
+		CLinkPrefsSelector* selfLink = new (ELeave) CLinkPrefsSelector(aSelectionPreferences);
+		self = selfLink;
+		selfCleanupItem = selfLink;
+		}
+	else
+	//399 selection
+		{
+		__CFLOG_VAR((KIpProtoTierMgrTag, KIpProtoTierMgrSubTag, _L8("TIpProtoProviderSelectorFactory::\tNewSelectorL() - 399 selector")));
+		CIpProtoProviderSelector* selfIPProto = new (ELeave) CIpProtoProviderSelector(aSelectionPreferences);
+		self = selfIPProto;
+		selfCleanupItem = selfIPProto;
+		}
+
+	CleanupStack::PushL(selfCleanupItem);
+	ASSERT(self->iTierRecord==NULL);
+	self->iTierRecord = TierManagerUtils::LoadTierRecordL(TUid::Uid(CIPProtoTierManagerFactory::iUid),*dbs);
+	CleanupStack::Pop(selfCleanupItem);
+	CleanupStack::Pop(dbs);
+	ASSERT(self->iDbs==NULL);
+	self->iDbs = dbs;
+	return self;
+	}
+
+